Repository navigation
Conversation
|
Thanks for covering the whitespace, Rust decode, shared image loader, and audio paths. The remaining blocker is CI maintenance: #21065 currently requires MIN_BASE_SHA 3fc7a66, and this branch is diverged from it, so check-maintenance fails before base-a-test-cpu can run. Could you please rebase onto current main (including that base) and push? Once CI runs, the current direct regression coverage should exercise the intended paths. |
|
@hanahhh I prepared the reviewer-requested fix that narrows the two filesystem OSError handlers to expected bad-path exceptions and adds coverage ensuring unexpected server-side errors (for example EMFILE) still propagate. The patch is available as commit efc607d on https://github.com/apex-mochen/sglang/tree/codex/review-40899-narrow-oserror. Please cherry-pick it, then rebase the branch onto current main before pushing so the maintenance gate can run the CPU tests. I will follow up on the two review threads once the update is present on this PR. |
…ultimodal input InklingMultimodalProcessor overrides process_mm_data_async() with its own media fetch (_resolve_media_item) and decode (_encode_image_bytes) steps, bypassing the CLIENT_MEDIA_EXCEPTIONS classification that sgl-project#31417 added to BaseMultimodalProcessor/common.py for every other VLM processor. As a result, an empty/unreachable image_url or an undecodable image raised an unclassified exception that the generic handler in serving_base.py mapped to HTTP 500 instead of 400. Apply the same classify-and-reraise-as-ValueError pattern used elsewhere: - reject an empty image_url at the boundary - reclassify requests.exceptions.RequestException from download_remote_media - reclassify OSError/UnidentifiedImageError from PIL's Image.open() Fixes sgl-project#40897
…ule docstring Minor cleanup, no behavior change.
…ication Address review feedback and audit findings on top of d170b24: - _resolve_media_item(): reject whitespace-only image_url, not just empty string (review feedback). - image_processing_rust.py::_pil_decode(): apply the same try/except OSError -> ValueError classification as _encode_image_bytes(). This is the actual default image decode path (SGLANG_INKLING_RS_MM_PREPROCESS defaults to True), so the earlier fix only covered the plain-Python fallback (review feedback). - image_processing.py::_load_image_bytes(): classify OSError from open() on a bad local path. Shared by both image decode paths and runs before either one, so a garbage image_url that isn't empty/data:/http(s):// was still reaching an unguarded open() and raising FileNotFoundError. - feature_extraction.py::_load_audio_bytes() / _decode_audio(): same class of gap, audio modality. _decode_audio wraps sf.read() to reclassify soundfile.LibsndfileError (a RuntimeError subclass), matching the pattern common.py::load_audio() already uses for the generic path. Adds regression tests for all of the above in test_inkling_media_errors.py.
1402178 to
f7a8aca
Compare
|
@apex-mochen Thanks for the contribution. I reviewed and cherry-picked your commit as f7a8aca (attribution preserved). Branch is also rebased onto current main now |
- _pil_decode() / _encode_image_bytes(): catch SyntaxError alongside
OSError. PIL raises SyntaxError (not OSError) for some structurally
valid but corrupt images (e.g. a truncated IDAT chunk), which were
still reaching the generic 500 handler.
- _load_image_bytes() / _load_audio_bytes(): switch the narrowed
except clause from an exception-type tuple to an errno check against
{ENOENT, ENOTDIR, EISDIR, ENAMETOOLONG}. The previous tuple missed
ENAMETOOLONG, so a raw base64 payload sent without a "data:" prefix
(treated as an overlong "path") still returned 500. Also truncate the
path in the error message, since it can hold an entire payload.
- _resolve_media_item(): truncate the url embedded in the error message
to 100 chars, matching the convention in
BaseMultimodalProcessor._load_single_item(). A truncated multi-MB
"data:" URL was otherwise echoed in full, both in logs and in the
400 response body. Also generalize the empty-URL message from
"empty image_url" to "empty media URL", since this function resolves
both image_data and audio_data.
- test_inkling_media_errors.py: consolidated redundant docstrings and
per-input __cause__ checks into the main assertions, added shared
_png_bytes()/_broken_chunk_png_bytes() helpers, and added regression
coverage for all of the above (SyntaxError, ENAMETOOLONG, message
truncation, generalized empty-URL message).
Addresses nvpohanh's review on PR sgl-project#40899.
|
/rerun-test test/registered/unit/multimodal/test_inkling_media_errors.py test/registered/e2e/models/test_inkling.py |
|
|
/rerun-test test/registered/unit/multimodal/test_inkling_media_errors.py test/registered/e2e/models/test_inkling.py |
|
🚀 🚀 |
|
Hi @hanahhh, since my contribution in f7a8aca may be lost as a separate commit if this PR is squash-merged, could you please preserve it in the final commit with: Co-authored-by: apex-mochen 2756823972@qq.com |
|
Hi @hanahhh, since my contribution in f7a8aca is an authored production-code commit and this PR may be squash-merged, could you please preserve my attribution in the final commit with: Co-authored-by: apex-mochen 2756823972@qq.com |
Preserve attribution for apex-mochen's contribution in f7a8aca (fix(inkling): preserve server file descriptor errors) when this PR is squash-merged. Co-authored-by: apex-mochen <2756823972@qq.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
[by Claude Code] @apex-mochen Thanks for the contribution. I merged the latest This repository squash-merges PRs, and GitHub carries |
|
/rerun-test test/registered/unit/multimodal/test_inkling_media_errors.py test/registered/e2e/models/test_inkling.py |
|
🚀 🚀 |
|
@TheDuyIT Could you take a look at the PR again and remove the "request change" if no other issues? |
|
@mickqian @yhyang201 Could you help to review this? Thanks! |
Motivation
Fixes #40897.
InklingMultimodalProcessoroverridesprocess_mm_data_async()with its own media-resolution step (_resolve_media_item()) and its own image-decode step (_encode_image_bytes()). Neither goes throughBaseMultimodalProcessor._load_single_item()/common.py::load_image(), so theCLIENT_MEDIA_EXCEPTIONSclassification added there by #31417 (which every other VLM processor inherits) never applied to Inkling. As a result, an empty/unreachableimage_urlor an undecodable image raised an unclassified exception that the generic handler inserving_base.pymapped to HTTP 500 instead of HTTP 400.Modifications
python/sglang/srt/multimodal/processors/inkling.py:_resolve_media_item()now rejects an emptyimage_urlat the boundary, and wraps thedata:/http(s)://branches intry/except CLIENT_MEDIA_EXCEPTIONS: raise ValueError(...)sorequests.exceptions.RequestExceptionfromdownload_remote_media()is reclassified as a client error instead of propagating raw.python/sglang/srt/multimodal/inkling/image_processing.py:_encode_image_bytes()wrapsImage.open(...)intry/except OSError as e: raise ValueError(...), mirroringcommon.py::_load_image().test/registered/unit/multimodal/test_inkling_media_errors.py(new): 11 cases covering both functions -- empty/unreachableimage_url, invalid base64, non-URL/plain-path passthrough, undecodable/truncated image bytes, and a valid-image regression guard.Accuracy Tests
N/A -- this only changes error handling for invalid client input; it does not touch model forward code or any path exercised by valid input.
Speed Tests and Profiling
N/A -- no hot-path/model-forward code touched.
Checklist
docs/describes Inkling's multimodal error-handling contract)CI States
Latest PR Test (Base): ❌ Run #37560765663
Latest PR Test (Extra): ❌ Run #37560765617
Latest PR Test (AMD ROCm 10): ❌ Run #37560765989