invoke-ai/InvokeAI · error · ValueError

Input videos have different frame rates; set Output FPS to r

Error message

Input videos have different frame rates; set Output FPS to retime them.

What it means

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.

Source

Thrown at invokeai/app/invocations/video_concat.py:196

                tmp_path.unlink(missing_ok=True)
            except Exception:
                pass

    def _estimate_transition_memory(self, width: int, height: int) -> int:
        if self.transition == "cut" or self.transition_frames == 0:
            return 0
        buffered_frames = self.transition_frames * (2 if self.transition == "crossfade" else 1)
        frame_bytes = width * height * 3
        return frame_bytes * (buffered_frames + _BLEND_WORKING_FRAMES)

    def _resolve_output_fps(self, source_rates: list[Optional[float]]) -> float:
        if self.fps is not None:
            return float(self.fps)
        known_rates = [rate for rate in source_rates if rate is not None and rate > 0]
        if not known_rates:
            return 16.0
        if any(not math.isclose(rate, known_rates[0], rel_tol=1e-3) for rate in known_rates[1:]):
            raise ValueError("Input videos have different frame rates; set Output FPS to retime them.")
        # An unknown rate mixed with agreeing known ones is not an error: probe_video
        # deliberately reports None for metadata-poor containers (VFR flags, missing
        # avg_frame_rate) whose real rate is usually the same as their neighbours'.
        # Erroring here would break previously-working concat workflows over a metadata
        # quirk; disagreement between *known* rates is the case that silently retimes.
        return known_rates[0]

    def _validate_transition_memory(self, width: int, height: int) -> None:
        estimated_bytes = self._estimate_transition_memory(width, height)
        if estimated_bytes > MAX_TRANSITION_MEMORY_BYTES:
            estimated_mib = estimated_bytes / (1024 * 1024)
            limit_mib = MAX_TRANSITION_MEMORY_BYTES / (1024 * 1024)
            raise ValueError(
                f"The requested transition needs an estimated {estimated_mib:.0f} MiB, "
                f"which exceeds the {limit_mib:.0f} MiB transition memory budget. "
                "Lower transition_frames or use lower-resolution clips."
            )

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Set the Output FPS field explicitly (e.g. 24 or 30) to retime all inputs to a common rate
  2. Normalize all inputs to the same fps before concatenating
  3. Accept the default only when all known source rates agree

Example fix

// before
VideoConcat(videos=[clip24, clip30])
// after
VideoConcat(videos=[clip24, clip30], fps=24)
Defensive patterns

Strategy: validation

Validate before calling

rates = [probe_video(p)[3] for p in paths]
known = [r for r in rates if r is not None and r > 0]
import math
if fps is None and len({r for r in known if math.isclose(r, known[0], rel_tol=1e-3)}) > 1:
    fps = known[0]  # must set Output FPS explicitly

Try / catch

try:
    output = concat.invoke(context)
except ValueError as e:
    if "different frame rates" in str(e):
        concat.fps = 24  # explicit common rate
        output = concat.invoke(context)
    else:
        raise

Prevention

When it happens

Trigger: Concatenating clips with fps 24 and 30 while leaving the fps field unset in the invocation.

Common situations: Mixing phone footage (30fps) with cinematic clips (24fps); mixing screen recordings (variable/odd rates); older workflow where fps field was left at default.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/e5a7fd12d49abb12. Report an issue: GitHub.