{"record":{"id":"f62d86dbdada23a0","repo":"sgl-project/sglang","slug":"num-frames-must-be-positive","errorCode":null,"errorMessage":"num_frames must be positive","messagePattern":"num_frames must be positive","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/configs/pipeline_configs/sana_video.py","lineNumber":69,"sourceCode":"                \"add_special_tokens\": True,\n            }\n        ]\n    )\n    preprocess_text_funcs: tuple[Callable[[str], str] | None, ...] = field(\n        default_factory=lambda: (None,)\n    )\n    postprocess_text_funcs: tuple[Callable, ...] = field(\n        default_factory=lambda: (sana_video_postprocess_text,)\n    )\n\n    def __post_init__(self) -> None:\n        self.vae_config.load_encoder = False\n        self.vae_config.load_decoder = True\n\n    def adjust_num_frames(self, num_frames: int) -> int:\n        temporal_scale = self.vae_config.arch_config.temporal_compression_ratio\n        if num_frames < 1:\n            raise ValueError(\"num_frames must be positive\")\n        return ((num_frames - 1) // temporal_scale) * temporal_scale + 1\n\n    def prepare_latent_shape(self, batch, batch_size, num_frames):\n        spatial_scale = self.vae_config.arch_config.spatial_compression_ratio\n        return (\n            batch_size,\n            self.dit_config.arch_config.num_channels_latents,\n            num_frames,\n            batch.height // spatial_scale,\n            batch.width // spatial_scale,\n        )\n\n    def get_latent_dtype(self, prompt_dtype: torch.dtype) -> torch.dtype:\n        return torch.float32\n\n    def get_pos_prompt_embeds(self, batch):\n        return batch.prompt_embeds[0]\n","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/configs/pipeline_configs/sana_video.py#L51-L87","documentation":"SANA video pipeline's frame-count adjuster only accepts num_frames >= 1; zero or negative frame counts raise immediately. Valid counts are then snapped to the VAE temporal grid via ((n-1)//temporal_scale)*temporal_scale + 1.","triggerScenarios":"Calling adjust_num_frames with num_frames=0 or negative — often from an int(input)/argparse default of 0, a computed frame count that underflowed (e.g. num_frames - temporal_scale below 1), or dividing/mis-parsing a duration parameter.","commonSituations":"CLI default frames=0 left unset; frame count derived from duration*fps where duration=0; downstream loop that repeatedly subtracts the temporal scale until below 1.","solutions":["Pass a positive frame count (at least temporal_scale+1 for a valid multi-frame video)","Fix upstream computation: frame_count = max(1, int(duration * fps))","Set argparse default to a valid value like 33 and use type=int with a check"],"exampleFix":"# before\nnum_frames = int(duration * fps)  # duration=0 -> 0\nnum_frames = pipe.adjust_num_frames(num_frames)  # error\n\n# after\nnum_frames = max(1, int(duration * fps))\nnum_frames = pipe.adjust_num_frames(num_frames)","handlingStrategy":"validation","validationCode":"if num_frames is None or num_frames < 1:\n    raise ValueError(\"num_frames must be >= 1\")\nnum_frames = pipe.adjust_num_frames(num_frames)","typeGuard":"def is_positive_int(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 1","tryCatchPattern":null,"preventionTips":["Clamp computed frame counts: max(1, int(duration * fps))","Give CLI/argparse a sane non-zero default","Remember the snap formula adds temporal_scale-1 slack; request frames accordingly"],"tags":["sana-video","video-generation","argument-validation","num-frames"],"backgroundTag":"invalid-argument-value","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}