{"record":{"id":"87bfb2033c4121aa","repo":"unslothai/unsloth","slug":"path-path-name-carries-no-video-track","errorCode":null,"errorMessage":"{Path(path).name} carries no video track.","messagePattern":"(.+?) carries no video track\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/diffusion_h3_clips.py","lineNumber":292,"sourceCode":"    The window is the FIRST ``num_frames`` of the source, and the latents are cached once for\n    the run, so a longer clip trains only its opening and its caption is paired with that. That\n    is the dataset contract -- pre-trim to the training duration -- but it used to be silent,\n    which is how a caption describing a whole scene ended up on its first second. ``on_note``\n    is called once per over-long clip with the numbers, so the run reports it.\n\n    ``waveform`` is a float32 array of shape ``(2, h3_audio_sample_count(num_frames))`` at\n    32 kHz. A mono source is duplicated to both channels; a clip with **no** audio track is\n    refused rather than silently trained as silence, because the audio rows are in the objective\n    and a silent target teaches the model to stop generating sound.\n    \"\"\"\n    import av\n    import numpy as np\n    from PIL import Image\n\n    target_samples = h3_audio_sample_count(num_frames)\n    with av.open(str(path)) as container:\n        if not container.streams.video:\n            raise ValueError(f\"{Path(path).name} carries no video track.\")\n        if not container.streams.audio:\n            raise ValueError(\n                f\"{Path(path).name} carries no audio track. MiniMax-H3 denoises video and audio \"\n                f\"in one packed sequence, so its training clips must have sound.\"\n            )\n        stream = container.streams.video[0]\n        source_fps = float(stream.average_rate or stream.guessed_rate or H3_FPS) or float(H3_FPS)\n        # Container duration, in seconds, for the over-long note below. Best effort: an unknown\n        # duration simply means no note, never a failed decode.\n        source_duration_s = 0.0\n        try:\n            if stream.duration is not None and stream.time_base is not None:\n                source_duration_s = float(stream.duration * stream.time_base)\n            elif getattr(container, \"duration\", None):\n                source_duration_s = float(container.duration) / 1_000_000.0\n        except Exception:  # noqa: BLE001 -- a note is not worth failing a decode over\n            source_duration_s = 0.0\n","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/diffusion_h3_clips.py#L274-L310","documentation":"Raised by decode_clip() (via av) when the opened container has no video stream at all. MiniMax-H3 training decodes video frames plus audio jointly, so a container without a video track cannot produce a training clip. The sibling check immediately after refuses audio-less files, so both halves of the packed sequence are enforced.","triggerScenarios":"Passing an audio-only file (.m4a/.mp3/.wav renamed or genuinely audio) or a still image wrapped in a container; a corrupt video file whose stream headers are unreadable but the container opens; an .avi/.mp4 whose video stream index is absent.","commonSituations":"Music/sfx folders accidentally included in a video training dir; motion-visualization exports that wrote audio only; files truncated during download so the video track is missing.","solutions":["Remove or exclude the audio-only/corrupt file from data_dir.","Re-encode the source to a normal .mp4 with both tracks (ffmpeg -i in.mp4 -c:v libx264 -c:a aac out.mp4) if the file was supposed to have video.","Pre-scan the dataset with av.open and skip files whose container.streams.video is empty, reporting them by name."],"exampleFix":"# before\n# data/sound_effect.mp3 in the training dir -> \"carries no video track\"\n\n# after\nimport av\nwith av.open(p) as c:\n    ok = bool(c.streams.video) and bool(c.streams.audio)\n# keep only ok files in the dataset","handlingStrategy":"validation","validationCode":"import av\n\ndef has_video_track(path: str) -> bool:\n    try:\n        with av.open(path) as c:\n            return bool(c.streams.video)\n    except av.error.InvalidDataError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    frames, waveform = decode_clip(p, num_frames=n, width=w, height=h)\nexcept ValueError as e:\n    if \"no video track\" in str(e):\n        skip_and_log(p)\n    else:\n        raise","preventionTips":["Pre-scan datasets with PyAV, keeping only files with both video and audio streams.","Keep audio-only media out of video training directories."],"tags":["video","dataset","codec","minimax-h3"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}