Fix image URL loading crashes and add a download timeout - #1
Open
BarneyChambers wants to merge 20 commits into
Open
BarneyChambers wants to merge 20 commits into
BarneyChambers wants to merge 20 commits into
Conversation
image_from_chunk raised an IndexError on data URLs without a comma, treated any URL starting with "file" (e.g. "file.png") as a local file path, and leaked the file handle it opened. download_image called requests.get without a timeout, so a hanging server blocked the encode path forever.
BarneyChambers
force-pushed
the
fix/image-url-loading
branch
from
September 7, 2026 13:48
9ff1d62 to
9090c97
Compare
Co-authored-by: ManoharPaturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Vibe Nuage Agent <vibe@mistral.ai>
…-gh-pages (mistralai#319) Co-authored-by: Vibe Nuage Agent <vibe@mistral.ai>
Co-authored-by: Vibe Nuage Agent <vibe@mistral.ai>
Co-authored-by: juliendenize <juliendenize@users.noreply.github.com>
Serving stacks cannot pass timeout= into encode_chat_completion. Read MISTRAL_COMMON_IMAGE_DOWNLOAD_TIMEOUT (default 10s), pass it explicitly from image_from_chunk, and name both knobs if the download times out.
…sage (mistralai#325) Co-authored-by: Vibe Nuage Agent <vibe@mistral.ai> Co-authored-by: juliendenize <juliendenize@users.noreply.github.com>
…malize (mistralai#316) (mistralai#321) Co-authored-by: Julien Denize <40604584+juliendenize@users.noreply.github.com> Co-authored-by: Vibe Nuage Agent <vibe@mistral.ai> Co-authored-by: juliendenize <juliendenize@users.noreply.github.com>
Co-authored-by: Julien Denize <40604584+juliendenize@users.noreply.github.com>
juliendenize
force-pushed
the
fix/image-url-loading
branch
from
September 21, 2026 10:12
f7bd87b to
ca1a36f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
image_from_chunkmishandles three of the four URL shapes it accepts, and the HTTP branch can hang forever.Deterministic:
This function is on the public encode path:
ImageEncoder.__call__->InstructTokenizerV3._encode_content_chunk->MistralTokenizer.encode_chat_completion, which is what vLLM and the TransformersMistralCommonBackendcall.ImageURLChunkcontent comes from the request, so all three inputs are attacker-supplied.Fixes mistralai#307
Real world example
A serving stack runs the experimental tokenize server (
mistral_common.experimental.app) or any framework that callsencode_chat_completionon user requests. A client sends:{"messages": [{"role": "user", "content": [ {"type": "image_url", "image_url": {"url": "data:image/png;base64"}} ]}]}What happens today:
image_from_chunksplits on ","IndexError: list index out of rangeValueError;IndexErrorescapes as an unhandled 500"url": "https://attacker.example/slow"requests.getnever returns; the encode worker is gone until restartThe
startswith("file")arm is quieter: a URL likefile.pngis opened relative to the server's working directory, so a name collision reads a local file instead of raising "Unsupported image url scheme". The handle is also never closed.After this fix: the malformed data URL and the bare
file.pngraiseRuntimeError(the same family the function already uses for unsupported schemes), and the HTTP branch gives up after 10 seconds with the existing "Error downloading the image" wrapping, sincerequests.exceptions.Timeoutis aRequestException.Fix
partition; raiseRuntimeErrorwhen there is no payload (covers both the missing comma and the empty payload).file://prefix for the local-file branch and open the file in awithblock (Image.load()before close), so bare names fall through to the unsupported-scheme error and the handle is closed. Behavior note: multi-frame images (GIF/TIFF) can no longer be seeked past frame 0 after return; the encoder only ever used frame 0, and the old code merely leaked the fd that made seeking possible.timeout(default 10.0s) fromdownload_imagetorequests.get. Exposed as a parameter so callers can tune it; existing error wrapping is unchanged.Not a duplicate
mistralai#289 and mistralai#294 fixed crashes in image sizing/config after loading; this PR is about loading itself. mistralai#259 touches audio data URL prefixes, different file.
Audio.from_urlhas the same missing timeout but a different grammar, so it stays out of scope here; flagged in the issue as follow-up.Test
No existing test covered malformed data URLs, bare file names, or the timeout (the two existing mocks accept any call signature). Added:
test_image_from_chunk_data_url_without_payload(both;base64and;base64,)test_image_from_chunk_bare_file_name_is_unsupportedtest_image_from_chunk_file_uri(regression guard for realfile://URIs)test_download_image_passes_timeout(assertstimeout=reachesrequests.get, and that aTimeoutbecomesRuntimeError)The first, second and fourth fail on
mainand pass with this change:Full unit suite:
uv run pytest tests/ --ignore=tests/integrations --ignore=tests/integration -n 4 --dist loadfile-> 1233 passed, 16 skipped. Doctests, ruff check, ruff format and mypy all pass on the changed files.Verification
main)RuntimeError;requests.getreceivestimeout=10.0file://URIs and mocked HTTP downloads still encode byte-identically (existingtest_download_image,test_image_encoder_formatsuntouched apart from mock signatures accepting the new kwarg)download_imageupdated with the newtimeoutarg; no other user-facing API change