{"record":{"id":"dfe419fed0e7aa99","repo":"sgl-project/sglang","slug":"shot-prompts-must-be-non-empty","errorCode":null,"errorMessage":"shot_prompts must be non-empty","messagePattern":"shot_prompts must be non-empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/causal_denoising.py","lineNumber":64,"sourceCode":"\nlogger = init_logger(__name__)\n\nCAUSAL_BLOCK_PROMPTS_KEY = \"causal_block_prompts\"\nCAUSAL_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","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/causal_denoising.py#L46-L82","documentation":"expand_causal_block_prompts requires at least one shot prompt to build causal block prompts; an empty shot_prompts list is rejected immediately.","triggerScenarios":"Calling expand_causal_block_prompts([], num_blocks=4) or a higher-level wrapper (expand_longlive2_shot_prompts / stage._block_prompts) receiving an empty prompt list from the request/config.","commonSituations":"Empty text prompt in a video generation request; config parsing yields empty shots list; user passes whitespace-only prompt that gets stripped to empty.","solutions":["Provide at least one non-empty shot prompt string","Validate prompts at the request boundary before reaching the pipeline","Check upstream prompt construction for accidental empty lists"],"exampleFix":"# before\nprompts = expand_causal_block_prompts([], num_blocks=8)\n# after\nprompts = expand_causal_block_prompts(['a cinematic shot of a fox'], num_blocks=8)","handlingStrategy":"validation","validationCode":"prompts = [p for p in shot_prompts if p and p.strip()]\nassert prompts, 'shot_prompts empty'","typeGuard":"def has_shots(prompts: list[str]) -> bool: return bool(prompts)","tryCatchPattern":null,"preventionTips":["Validate non-empty prompt at the HTTP/request boundary with a 400 response"],"tags":["prompt-validation","causal-denoising"],"backgroundTag":"empty-input-list","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}