Skip to content

fix(video): only send output_dtype to TorchCodec when it is not the default - #232

Merged
lfengad merged 1 commit into
release/2026-09-03-3f2febdbfrom
liangf/fix-torchcodec-output-dtype
Sep 3, 2026
Merged

fix(video): only send output_dtype to TorchCodec when it is not the default#232
lfengad merged 1 commit into
release/2026-09-03-3f2febdbfrom
liangf/fix-torchcodec-output-dtype

Conversation

@lfengad

@lfengad lfengad commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

What

Fixes the generator-inference-smoke failure on #231.

_build_decoder forwards output_dtype=torch.uint8 into VideoDecoder(...) on every call:

kwargs: dict[str, Any] = {"num_ffmpeg_threads": num_ffmpeg_threads, "output_dtype": output_dtype}

output_dtype does not exist on the pinned TorchCodec. pyproject.toml resolves cu128 and cu130 to torchcodec==0.10.0, whose VideoDecoder.__init__ is:

def __init__(self, source, *, stream_index=None, dimension_order="NCHW",
             num_ffmpeg_threads=1, device=None, seek_mode="exact",
             transforms=None, custom_frame_mappings=None):

Only the cu130-torch213 group pins a release new enough (0.14.0). Every CI job runs --group=cu128-train, so every decoder construction — including plain metadata probes via probe_video() — raised:

TypeError: VideoDecoder.__init__() got an unexpected keyword argument 'output_dtype'

uint8 is already 0.10's native output, so the default carried no information and only broke the call.

Why the failure was so expensive to read

In test_nano_inference_omni it was rank 1 that raised. The other three ranks carried on into an ALLREDUCE and sat there until the 1800s NCCL watchdog fired, at which point ProcessGroupNCCL took them down with SIGABRT (exitcode -6, traceback: NoneType: None). 30 of the job's 36 minutes were the timeout, and the real one-line TypeError was ~950 lines above the reported failure.

The same bug in test_nano_inference_multi_control_transfer hit rank 0 and failed cleanly in ~14 seconds — same root cause, completely different-looking failure, decided purely by which rank got there first.

The fix

  • Send output_dtype only when it differs from the uint8 default, restoring the default path to its pre-regression behaviour.
  • Translate a rejected output_dtype / transforms keyword into a message naming the knob and the installed version, so a genuine request on an old build fails legibly instead of as a bare TypeError deep inside a rank.

No caller anywhere in the repo passes output_dtype or resize_size, so nothing loses functionality. transforms does exist on 0.10.0 and is unaffected; it is covered by the same guard for older builds.

interleaved_video_parsing.py already carries this exact defensive pattern (_SUPPORTS_VIDEO_DECODER_OUTPUT_DTYPE, the cached TypeError probe). It just was not applied to torchcodec_video.py.

Tests

torchcodec_video.py had no test file at all — which is why a pure-Python signature mismatch had to be caught by a 4-GPU inference smoke test instead of a unit test.

Adds torchcodec_video_test.py (6 tests). The decoders in it mirror the real 0.10.0 and newer signatures rather than whatever CI resolved, so the behaviour is pinned on both. Verified red→green: the 3 compatibility tests fail against the current code with the exact production error (torchcodec_video.py:59) and pass after the fix. ruff check and ruff format --check are clean on both files.

Base

Targets release/2026-09-03-3f2febdb so #231 can go green.

🤖 Generated with Claude Code

…efault

_build_decoder passed output_dtype=torch.uint8 into VideoDecoder(...) on every
call. That parameter does not exist on the pinned cu128/cu130 TorchCodec
(0.10.0) -- it first appears in 0.14.0, and cu128 wheels stop at 0.11.1, so no
pin bump can make the code as written work on cu128 -- and every decoder
construction raised

    TypeError: VideoDecoder.__init__() got an unexpected keyword argument
    'output_dtype'

including plain metadata probes through probe_video(). uint8 is already
TorchCodec's own default, so the keyword carried no information and only broke
the call.

This took down generator-inference-smoke, and did so expensively: in
test_nano_inference_omni it was rank 1 that raised, so the other three ranks sat
in an ALLREDUCE until the 1800s NCCL watchdog fired and ProcessGroupNCCL aborted
them (SIGABRT, no Python traceback). The real one-line TypeError was ~950 lines
above the reported failure.

Send output_dtype only when it differs from the uint8 default, and translate a
rejected output_dtype/transforms keyword into a message naming the knob and the
installed version, so a genuine request on an old build fails legibly instead of
as a bare TypeError deep inside a rank.

No caller passes output_dtype or resize_size, so the default path is restored to
its pre-regression behaviour. transforms does exist on 0.10.0 and is unaffected;
it is covered by the same guard for older builds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lfengad
lfengad force-pushed the liangf/fix-torchcodec-output-dtype branch from 55fffa1 to 54e2e8b Compare September 3, 2026 14:33
@lfengad
lfengad merged commit df72c92 into release/2026-09-03-3f2febdb Sep 3, 2026
1 check passed
@lfengad
lfengad deleted the liangf/fix-torchcodec-output-dtype branch September 3, 2026 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant