{"record":{"id":"f69a527d220d306b","repo":"sgl-project/sglang","slug":"num-frames-must-be-divisible-by-num-frames-per-blo","errorCode":null,"errorMessage":"num_frames must be divisible by num_frames_per_block for causal DMD denoising","messagePattern":"num_frames must be divisible by num_frames_per_block for causal DMD denoising","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/causal_denoising.py","lineNumber":1242,"sourceCode":"                    crossattn_cache=self.crossattn_cache,\n                    current_start_frame=current_start_frame,\n                    image_kwargs=image_kwargs,\n                    pos_cond_kwargs=pos_cond_kwargs,\n                    target_dtype=target_dtype,\n                    autocast_enabled=autocast_enabled,\n                )\n                current_start_frame += block\n                remaining_frames -= block\n\n        # Base position offset from any cache warm-up\n        pos_start_base = current_start_frame\n\n        # Determine block sizes\n        if not independent_first_frame or (\n            independent_first_frame and batch.image_latent is not None\n        ):\n            if t % self.num_frames_per_block != 0:\n                raise ValueError(\n                    \"num_frames must be divisible by num_frames_per_block for causal DMD denoising\"\n                )\n            num_blocks = t // self.num_frames_per_block\n            block_sizes = [self.num_frames_per_block] * num_blocks\n            start_index = 0\n        else:\n            if (t - 1) % self.num_frames_per_block != 0:\n                raise ValueError(\n                    \"(num_frames - 1) must be divisible by num_frame_per_block when independent_first_frame=True\"\n                )\n            num_blocks = (t - 1) // self.num_frames_per_block\n            block_sizes = [1] + [self.num_frames_per_block] * num_blocks\n            start_index = 0\n\n        def prepare_context_input(current_latents):\n            return current_latents\n\n        # DMD loop in causal blocks","sourceCodeStart":1224,"sourceCodeEnd":1260,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/causal_denoising.py#L1224-L1260","documentation":"In causal DMD denoising forward, when the first frame is not independent (or image conditioning latents are present), total frame count t must be divisible by num_frames_per_block so blocks tile evenly.","triggerScenarios":"num_frames=100 with num_frames_per_block=25 fails (100%25==0 passes); e.g. num_frames=50 with block 24 → ValueError during forward.","commonSituations":"Requesting arbitrary clip lengths (e.g. 4.1s at 24fps); block size from model config (e.g. 25 for 1s@25fps) mismatched with requested frames; image-to-video paths that include the conditioned frame in t.","solutions":["Set num_frames to a multiple of num_frames_per_block","Adjust num_frames_per_block to a divisor of your frame count","Enable independent_first_frame (and no image conditioning) so (t-1) must be divisible instead"],"exampleFix":"# before\nreq.num_frames = 50  # block=25\n# after\nreq.num_frames = 50; req.num_frames_per_block = 25  # ok; or use 48 with block 24","handlingStrategy":"validation","validationCode":"assert num_frames % num_frames_per_block == 0","typeGuard":"def frames_ok(t: int, block: int, indep: bool, has_img: bool) -> bool:\n    return (t - 1) % block == 0 if (indep and not has_img) else t % block == 0","tryCatchPattern":null,"preventionTips":["Snap requested durations to whole blocks at the API layer","Expose num_frames_per_block in your request validation schema"],"tags":["causal-denoising","frame-count","divisibility"],"backgroundTag":"divisibility-constraint-violated","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}