Repository navigation
Return 400 for a bad upload and 500 for a server fault - #395
vasilevklart wants to merge 3 commits into
Conversation
Output failures are always 500. An upload that won't decode is a 400, and client knobs read only in postprocess (image format, fps) are checked at intake.
Live test: api: 400 for bad uploads, 500 past intakeWorks. A corrupt or truncated upload is now a 400 (base 500), for Qwen3.5 chat images and FLUX.2 edits. Bad FLUX.2 output knobs and a NaN Wan 2.2 1x H200 · Claims
Other
|
Gaurav-Shah05
left a comment
There was a problem hiding this comment.
The output half needs no changes.
Chatterbox's _decode_audio has the same problem on main: a missing FFmpeg returns 400, though its comment says that stays a server error. The library check from the inline comment would fix it too, so I'd include it here.
I merged this PR onto main, served Qwen3.5-0.8B on one H100, and ran each model's loader on good and bad files. Since #633 Model.load_image returns 400 for a corrupt image, but the other image, video and audio loaders still return 500.
| becomes a ValueError, so the client gets a 400 instead of a 500.""" | ||
| try: | ||
| return load(filepath, device) | ||
| except _DECODE_ERRORS as exc: |
There was a problem hiding this comment.
This catch spans the whole loader, so a server failure inside it, like torchcodec failing to load FFmpeg or a failed allocation in Model.load_image, returns a 400 where main returns 500. I think each loader should raise the ValueError at its decode call, after a once-per-process check that its decoder library loads.
main moved the media load into _load_media and request intake into _process_waiting_input, and added a stream-input intake path and client_error_text. Intake failures (preprocessing and stream input) pass intake=True, so a ValueError there stays a 400; a 500 past intake no longer shows the exception text (client_error_text's refusal follows the status). Tests that call _fail_request for preprocessing pass intake=True, and an inline-token or pooled-encode postprocess failure is now a 500.
The data worker's catch spanned the whole loader, so a failed allocation or a torchcodec without FFmpeg could become a 400 as well. Each loader now wraps only its decode call in media_limits.decoding_upload: a file the decoder refuses is an UndecodableMediaError (a 400), and a failed allocation, a removed upload and a missing FFmpeg are re-raised (a 500). FLUX.2, LingBot-World, Waypoint, the base audio and video loaders, OmniVoice, Fish S2-Pro, Qwen3-TTS and V-JEPA 2 now answer a corrupt file with a 400 (500 on main); Chatterbox, CosyVoice3 and Qwen3.5 video without FFmpeg, and the base image loader and load_speech_file on a failed allocation, with a 500 (400 on main). Cosmos3 still retries a refused file with PyAV.
|
@vasilevklart does this need to stay open? or is this fixed by any upstream PR? |
The data worker picked 400 or 500 from the exception type at every stage. Most media loaders let a corrupt upload's decoder error through as a 500, a few turned a server fault into a 400, and a
ValueErrorfrom output postprocessing (a server bug) was a 400. Part of #394, from the #275 review.Each loader now wraps only its decode call in
decoding_upload(media_limits.py): the decoder refusing the file is a 400, while a failed allocation, a removed upload and a torchcodec without FFmpeg stay 500s. Past intake every failure is a 500 with no exception text, so the image output knobs (FLUX.2, Z-Image) andfps(Wan2.2, Cosmos3) are checked at intake instead. Both frontends take the status from the data worker, so the Rust side is unchanged.Model.load_image(Qwen3.5, Qwen3-Omni, BAGEL)Model.load_audio(Qwen3-Omni), OmniVoiceload_speech_file(Whisper, Qwen3-ASR, Canary, Parakeet)Model.load_video, V-JEPA 2ValueError: 400 → 500Bad files: truncated PNG/JPEG, garbage WAV/M4A/MP4 (a torchcodec stand-in refuses them where FFmpeg decodes). No FFmpeg: torchcodec 0.10 on a host without it. Allocation: a real 2^62-byte one inside the decoder.
Tests:
test_api_completion_guard.pyruns 20 cases through the real loaders (11 bad files → 400, 9 server faults → 500); 12 fail on main. CPU Core fails the same tests as main, by name. ruff clean. Not run: a GPU server (the loaders run on the API server's CPU).AI assistance (Claude) was used for this PR.