{"record":{"id":"b6d50864c6e7a7af","repo":"unslothai/unsloth","slug":"no-captioned-video-clips-found-minimax-h3-trains","errorCode":null,"errorMessage":"No captioned video clips found. MiniMax-H3 trains from clips with sound, not stills: provide .mp4 / .mov / .mkv / .webm files plus a metadata.jsonl / captions.jsonl, per-clip .txt captions, or an instance prompt.","messagePattern":"No captioned video clips found\\. MiniMax-H3 trains from clips with sound, not stills: provide \\.mp4 / \\.mov / \\.mkv / \\.webm files plus a metadata\\.jsonl / captions\\.jsonl, per-clip \\.txt captions, or an instance prompt\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/diffusion_h3_clips.py","lineNumber":250,"sourceCode":"            sidecar = clip.with_suffix(ext)\n            if sidecar.is_file():\n                sidecar_present = True\n                try:\n                    caption = sidecar.read_text(encoding = \"utf-8\").strip()\n                except (OSError, UnicodeError):\n                    caption = \"\"\n                break\n        if not sidecar_present:\n            caption = meta_caption.get(clip.name) or meta_caption.get(\n                clip.relative_to(root).as_posix()\n            )\n        if not caption and instance_prompt:\n            caption = instance_prompt\n        if caption:\n            pairs.append((str(clip), caption))\n\n    if not pairs:\n        raise ValueError(\n            \"No captioned video clips found. MiniMax-H3 trains from clips with sound, not \"\n            \"stills: provide .mp4 / .mov / .mkv / .webm files plus a metadata.jsonl / \"\n            \"captions.jsonl, per-clip .txt captions, or an instance prompt.\"\n        )\n    return pairs\n\n\ndef decode_clip(\n    path: str | os.PathLike[str],\n    *,\n    num_frames: int,\n    width: int,\n    height: int,\n    on_note: Optional[Callable[[str], None]] = None,\n) -> tuple[Any, Any]:\n    \"\"\"Decode one training clip to ``(frames, waveform)``.\n\n    ``frames`` is a uint8 numpy array of shape ``(num_frames, height, width, 3)`` resampled onto","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/diffusion_h3_clips.py#L232-L268","documentation":"Raised by H3 clip discovery when the directory exists but zero (clip, caption) pairs were assembled. Clips only count when they carry a caption: a <stem>.txt/.caption sidecar, a metadata.jsonl/captions.jsonl row, or the dreambooth instance_prompt fallback. It also encodes that MiniMax-H3 trains from video with sound, not stills, so image-only or caption-less folders fail here.","triggerScenarios":"An empty directory; a folder of .mp4 files with no captions and no instance_prompt; captions keyed by a filename that doesn't match any clip's name or relative path; only images (.jpg) present; a metadata.jsonl that failed to parse (its OSError/UnicodeError is swallowed, leaving no captions).","commonSituations":"Pointing data_dir at the parent folder instead of the clips folder; caption files named clip-1.txt for clip_1.mp4; a UTF-16-encoded metadata.jsonl that silently fails to read; forgetting to set an instance prompt for dreambooth-style runs.","solutions":["Add per-clip <stem>.txt caption sidecars or a valid UTF-8 metadata.jsonl/captions.jsonl with file_name + caption_column rows.","Or set an instance_prompt so every clip falls back to it.","Verify the folder actually contains .mp4/.mov/.mkv/.webm files and that caption keys exactly match clip names (or relative POSIX paths)."],"exampleFix":"# before\n# data/myclip.mp4 with no caption anywhere, instance_prompt=None -> ValueError\n\n# after\n# data/myclip.txt containing the caption text\ncfg.instance_prompt = \"a skateboarder in slow motion\"  # or per-clip sidecars","handlingStrategy":"validation","validationCode":"from pathlib import Path\nVIDEO_EXTS = {\".mp4\", \".mov\", \".mkv\", \".webm\", \".m4v\", \".avi\"}\n\ndef dataset_has_captioned_clips(data_dir: str, instance_prompt: str | None) -> bool:\n    root = Path(data_dir).expanduser()\n    clips = [p for p in root.iterdir() if p.is_file() and p.suffix.lower() in VIDEO_EXTS]\n    if not clips:\n        return False\n    if instance_prompt and instance_prompt.strip():\n        return True\n    return any((p.with_suffix(\".txt\").is_file() or p.with_suffix(\".caption\").is_file()) for p in clips)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ship datasets with per-clip .txt sidecars named exactly <stem>.txt, or a UTF-8 metadata.jsonl.","Set an instance_prompt as a universal fallback so caption bookkeeping can't zero out the dataset.","Key metadata rows by exact file names or relative POSIX paths."],"tags":["dataset","captions","video","training"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}