{"record":{"id":"8c9a5e1b95bbfc4a","repo":"sgl-project/sglang","slug":"generated-minimax-h3-mp4-frame-rate-must-be-minim","errorCode":null,"errorMessage":"generated MiniMax H3 MP4 frame rate must be {MINIMAX_H3_SUPPORTED_FPS} fps, got {rate_raw!r}","messagePattern":"generated MiniMax H3 MP4 frame rate must be (.+?) fps, got (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/video_adapter.py","lineNumber":447,"sourceCode":"        raise RuntimeError(\n            f\"generated MiniMax H3 MP4 has invalid size {width}x{height}\"\n        )\n    if expected_size is not None and (width, height) != expected_size:\n        raise RuntimeError(\n            \"generated MiniMax H3 MP4 size does not match the resolved request: \"\n            f\"expected {expected_size[0]}x{expected_size[1]}, got {width}x{height}\"\n        )\n    rate_raw = str(video_stream.get(\"avg_frame_rate\") or \"\")\n    try:\n        if \"/\" in rate_raw:\n            numerator, denominator = rate_raw.split(\"/\", 1)\n            fps = float(numerator) / float(denominator)\n        else:\n            fps = float(rate_raw)\n    except (TypeError, ValueError, ZeroDivisionError):\n        fps = 0.0\n    if abs(fps - float(MINIMAX_H3_SUPPORTED_FPS)) > 1e-6:\n        raise RuntimeError(\n            \"generated MiniMax H3 MP4 frame rate must be \"\n            f\"{MINIMAX_H3_SUPPORTED_FPS} fps, got {rate_raw!r}\"\n        )\n    try:\n        audio_sample_rate = int(audio_stream.get(\"sample_rate\") or 0)\n    except (TypeError, ValueError):\n        audio_sample_rate = 0\n    expected_sample_rate = MiniMaxH3PipelineConfig.output_audio_sample_rate\n    if expected_sample_rate is not None and audio_sample_rate != expected_sample_rate:\n        raise RuntimeError(\n            \"generated MiniMax H3 MP4 audio sample rate must be \"\n            f\"{expected_sample_rate} Hz, \"\n            f\"got {audio_sample_rate}\"\n        )\n    try:\n        audio_channels = int(audio_stream.get(\"channels\") or 0)\n    except (TypeError, ValueError):\n        audio_channels = 0","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/video_adapter.py#L429-L465","documentation":"Raised by the MiniMax H3 video adapter after probing a generated MP4: the container's video stream reports a frame rate that does not equal MINIMAX_H3_SUPPORTED_FPS. The pipeline validates its own generated output as a sanity check; a mismatch means the muxing/encoding path produced an unexpected fps (or the fps could not be parsed and defaulted to 0.0).","triggerScenarios":"Calling the MiniMax H3 video pipeline and probing the output MP4 via _probe_minimax_h3_output_fields / probe_output; triggers when the MP4 stream's avg_frame_rate or r_frame_rate (a 'num/den' Fraction, numeric, or malformed value) does not parse to the supported fps constant within 1e-6.","commonSituations":"A codec/container library change altering how frame rate is written or reported, a custom muxer writing r_frame_rate as '0/0' (caught and turned into fps=0.0), or the model config's supported fps constant being changed without updating the encoder settings.","solutions":["Inspect the generated MP4 with ffprobe to see the actual avg_frame_rate/r_frame_rate and confirm what value the encoder wrote","Ensure the muxing stage sets the stream frame rate to exactly MINIMAX_H3_SUPPORTED_FPS (matching numerator/denominator, not a decimal approximation)","If rate parsing failed (TypeError/ValueError/ZeroDivisionError path yields fps=0.0), fix the container metadata so avg_frame_rate is a valid non-zero fraction","If the fps constant legitimately changed, update MINIMAX_H3_SUPPORTED_FPS and the encoder together"],"exampleFix":"// before\nstream.set(avg_frame_rate=25.0)  // float, muxer may round\n// after\nfrom fractions import Fraction\nfps = MINIMAX_H3_SUPPORTED_FPS\nstream.set(avg_frame_rate=Fraction(fps).limit_denominator(10**6))","handlingStrategy":"validation","validationCode":"import subprocess, json\nfrom fractions import Fraction\nprobe = subprocess.run(['ffprobe','-v','error','-select_streams','v:0','-show_entries','stream=avg_frame_rate','-of','json', mp4_path], capture_output=True, text=True)\nrate = json.loads(probe.stdout)['streams'][0]['avg_frame_rate']\nnum, den = map(int, rate.split('/'))\nassert abs(num/den - MINIMAX_H3_SUPPORTED_FPS) < 1e-6, f'fps mismatch: {rate}'","typeGuard":null,"tryCatchPattern":"try:\n    probe_output(mp4)\nexcept RuntimeError as e:\n    if 'frame rate' in str(e):\n        logger.warning('regenerating with explicit fps metadata: %s', e)\n        remux_with_fps(mp4, MINIMAX_H3_SUPPORTED_FPS)\n    else:\n        raise","preventionTips":["Always set stream frame rate with an exact Fraction, never a float","Run ffprobe on the first output of any new encoder/muxer configuration in CI","Unit-test _probe_minimax_h3_output_fields against synthetic MP4s with known rates"],"tags":["minimax-h3","video","fps","mp4","validation"],"backgroundTag":"output-format-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}