{"record":{"id":"e5a7fd12d49abb12","repo":"invoke-ai/InvokeAI","slug":"input-videos-have-different-frame-rates-set-outpu","errorCode":null,"errorMessage":"Input videos have different frame rates; set Output FPS to retime them.","messagePattern":"Input videos have different frame rates; set Output FPS to retime them\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/video_concat.py","lineNumber":196,"sourceCode":"                tmp_path.unlink(missing_ok=True)\n            except Exception:\n                pass\n\n    def _estimate_transition_memory(self, width: int, height: int) -> int:\n        if self.transition == \"cut\" or self.transition_frames == 0:\n            return 0\n        buffered_frames = self.transition_frames * (2 if self.transition == \"crossfade\" else 1)\n        frame_bytes = width * height * 3\n        return frame_bytes * (buffered_frames + _BLEND_WORKING_FRAMES)\n\n    def _resolve_output_fps(self, source_rates: list[Optional[float]]) -> float:\n        if self.fps is not None:\n            return float(self.fps)\n        known_rates = [rate for rate in source_rates if rate is not None and rate > 0]\n        if not known_rates:\n            return 16.0\n        if any(not math.isclose(rate, known_rates[0], rel_tol=1e-3) for rate in known_rates[1:]):\n            raise ValueError(\"Input videos have different frame rates; set Output FPS to retime them.\")\n        # An unknown rate mixed with agreeing known ones is not an error: probe_video\n        # deliberately reports None for metadata-poor containers (VFR flags, missing\n        # avg_frame_rate) whose real rate is usually the same as their neighbours'.\n        # Erroring here would break previously-working concat workflows over a metadata\n        # quirk; disagreement between *known* rates is the case that silently retimes.\n        return known_rates[0]\n\n    def _validate_transition_memory(self, width: int, height: int) -> None:\n        estimated_bytes = self._estimate_transition_memory(width, height)\n        if estimated_bytes > MAX_TRANSITION_MEMORY_BYTES:\n            estimated_mib = estimated_bytes / (1024 * 1024)\n            limit_mib = MAX_TRANSITION_MEMORY_BYTES / (1024 * 1024)\n            raise ValueError(\n                f\"The requested transition needs an estimated {estimated_mib:.0f} MiB, \"\n                f\"which exceeds the {limit_mib:.0f} MiB transition memory budget. \"\n                \"Lower transition_frames or use lower-resolution clips.\"\n            )\n","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/video_concat.py#L178-L214","documentation":"When the Output FPS field is not set, video_concat must pick a frame rate. If the probed source rates disagree (beyond rel_tol 1e-3), concatenating would silently retime clips, so it raises ValueError and asks the user to set Output FPS explicitly. Unknown (None) rates mixed with agreeing known rates are tolerated per the documented probe_video behavior.","triggerScenarios":"Concatenating clips with fps 24 and 30 while leaving the fps field unset in the invocation.","commonSituations":"Mixing phone footage (30fps) with cinematic clips (24fps); mixing screen recordings (variable/odd rates); older workflow where fps field was left at default.","solutions":["Set the Output FPS field explicitly (e.g. 24 or 30) to retime all inputs to a common rate","Normalize all inputs to the same fps before concatenating","Accept the default only when all known source rates agree"],"exampleFix":"// before\nVideoConcat(videos=[clip24, clip30])\n// after\nVideoConcat(videos=[clip24, clip30], fps=24)","handlingStrategy":"validation","validationCode":"rates = [probe_video(p)[3] for p in paths]\nknown = [r for r in rates if r is not None and r > 0]\nimport math\nif fps is None and len({r for r in known if math.isclose(r, known[0], rel_tol=1e-3)}) > 1:\n    fps = known[0]  # must set Output FPS explicitly","typeGuard":null,"tryCatchPattern":"try:\n    output = concat.invoke(context)\nexcept ValueError as e:\n    if \"different frame rates\" in str(e):\n        concat.fps = 24  # explicit common rate\n        output = concat.invoke(context)\n    else:\n        raise","preventionTips":["Always set Output FPS when mixing footage from different sources","Normalize all clips to one fps in a preprocessing step","Probe source fps (ffprobe avg_frame_rate) before building the graph"],"tags":["video","framerate","invokeai"],"backgroundTag":"framerate-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}