{"record":{"id":"b20f7f4acd732f2d","repo":"sgl-project/sglang","slug":"shot-durations-must-match-shot-prompts-length","errorCode":null,"errorMessage":"shot_durations must match shot_prompts length","messagePattern":"shot_durations must match shot_prompts length","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/causal_denoising.py","lineNumber":68,"sourceCode":"CAUSAL_SCENE_CUT_MASK_KEY = \"causal_scene_cut_mask\"\nCAUSAL_SHOT_INDICES_KEY = \"causal_shot_indices\"\nCausalKVCache = CausalSelfAttentionKVCache | QVGPackedCausalKVCache\n\n\ndef expand_causal_block_prompts(\n    shot_prompts: list[str],\n    *,\n    num_blocks: int,\n    shot_durations: list[int] | None = None,\n    chunks_per_shot: int = 0,\n    scene_cut_prefix: str = \"\",\n) -> tuple[list[str], list[bool], list[int]]:\n    if not shot_prompts:\n        raise ValueError(\"shot_prompts must be non-empty\")\n    if num_blocks <= 0:\n        raise ValueError(\"num_blocks must be positive\")\n    if shot_durations is not None and len(shot_durations) != len(shot_prompts):\n        raise ValueError(\"shot_durations must match shot_prompts length\")\n\n    if shot_durations is not None:\n        durations = shot_durations[: len(shot_prompts)]\n    elif chunks_per_shot > 0:\n        durations = [chunks_per_shot] * len(shot_prompts)\n    else:\n        base, extra = divmod(num_blocks, len(shot_prompts))\n        durations = [base + (1 if i < extra else 0) for i in range(len(shot_prompts))]\n\n    clamped: list[int] = []\n    remaining = num_blocks\n    for duration in durations:\n        if remaining <= 0:\n            break\n        take = min(int(duration), remaining)\n        clamped.append(take)\n        remaining -= take\n    if remaining > 0 and clamped:","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/causal_denoising.py#L50-L86","documentation":"When shot_durations is provided to expand_causal_block_prompts it must have exactly one duration per shot prompt; mismatched lengths are rejected because block allocation depends on per-shot durations.","triggerScenarios":"expand_causal_block_prompts(prompts, num_blocks=n, shot_durations=[4]) with 3 prompts.","commonSituations":"Prompt list and duration list built from different sources (prompts from request, durations from config); adding a prompt without updating durations; trailing empty shot filtered from one list but not the other.","solutions":["Make len(shot_durations) == len(shot_prompts)","Drop shot_durations and use chunks_per_shot for uniform durations"],"exampleFix":"# before\nexpand_causal_block_prompts(['a','b','c'], 8, shot_durations=[4])\n# after\nexpand_causal_block_prompts(['a','b','c'], 8, shot_durations=[4,4,4])","handlingStrategy":"validation","validationCode":"assert shot_durations is None or len(shot_durations) == len(shot_prompts)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate prompts and durations from a single shots list structure"],"tags":["prompt-validation","length-mismatch","causal-denoising"],"backgroundTag":"argument-length-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}