invoke-ai/InvokeAI · error · ValueError
Input videos are {width}x{height}; H.264 encoding requires e
Error message
Input videos are {width}x{height}; H.264 encoding requires even dimensions. Re-encode or crop the sources to even width and height first. What it means
H.264 (libx264 + yuv420p) requires even width and height. video_concat keeps source dimensions exactly (macro_block_size=1), so it rejects odd-dimension inputs up front with a descriptive ValueError instead of silently resizing.
Source
Thrown at invokeai/app/invocations/video_concat.py:134
def invoke(self, context: InvocationContext) -> VideoOutput:
if len(self.videos) < 2:
raise ValueError("video_concat requires at least two input videos.")
paths: list[Path] = [context.videos.get_path(v.video_name) for v in self.videos]
# Probe inputs up front: enforce matching dims and pick the default output fps.
probes = [probe_video(p) for p in paths]
widths = {(w, h) for (w, h, _, _) in probes}
if len(widths) > 1:
raise ValueError(
f"All inputs must share the same dimensions. Got: "
f"{sorted(widths)}. Re-render at a single resolution before concatenating."
)
width, height, _, _first_fps = probes[0]
# libx264 + yuv420p needs even dimensions; we encode with macro_block_size=1 to
# preserve the source dimensions exactly, so reject odd sources with a clear error.
if width % 2 or height % 2:
raise ValueError(
f"Input videos are {width}x{height}; H.264 encoding requires even dimensions. "
"Re-encode or crop the sources to even width and height first."
)
self._validate_transition_memory(width, height)
output_fps = self._resolve_output_fps([probe[3] for probe in probes])
context.util.signal_progress(f"Joining {len(self.videos)} clip(s) ({self.transition}) @ {output_fps:.2f} fps")
tmp = tempfile.NamedTemporaryFile(prefix="invokeai_video_concat_", suffix=".mp4", delete=False)
tmp.close()
tmp_path = Path(tmp.name)
try:
# Frames stream from the decoders straight into the encoder; only the
# transition windows are buffered. See _iter_joined_frames.
writer = make_mp4_writer(tmp_path, output_fps)
num_frames = 0
try:
clip_iters = [iter_video_frames(p, is_canceled=context.util.is_canceled) for p in paths]View on GitHub (pinned to 0b6a024f2f)
Solutions
- Re-encode or crop sources so both width and height are even (e.g. crop 853x480 to 852x480)
- Apply a crop/scale node in the workflow before video_concat
- Use ffmpeg: -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" to make dimensions even
Example fix
// before videos=[clip_853x480] // after # pre-process: ffmpeg -i in.mp4 -vf crop=trunc(iw/2)*2:trunc(ih/2)*2 even.mp4 videos=[clip_852x480]
Defensive patterns
Strategy: validation
Validate before calling
w, h = probe_video(path)[:2]
if w % 2 or h % 2:
raise ValueError(f"{path} is {w}x{h}; crop/scale to even dimensions before concat") Type guard
def has_even_dimensions(w: int, h: int) -> bool:
return w % 2 == 0 and h % 2 == 0 Try / catch
try:
output = concat.invoke(context)
except ValueError as e:
if "requires even dimensions" in str(e):
videos = [reencode_even(v) for v in videos] # ffmpeg crop=trunc(iw/2)*2:trunc(ih/2)*2
output = concat.invoke(context)
else:
raise Prevention
- After cropping, round crop sizes down to even numbers
- Prefer scales like 1920x1080/1280x720; avoid 1-pixel-off exports
- Add a pre-flight ffprobe check for odd dimensions in automation scripts
When it happens
Trigger: Concatenating videos whose width or height is odd, e.g. 853x480 or 1920x1081.
Common situations: Cropped screen recordings with odd crop sizes; legacy footage at odd dimensions; images-to-video pipelines producing 1-pixel-off sizes.
Related errors
- Video {video_name} is {width}x{height}; H.264 encoding requi
- Video must use a browser-compatible H.264/AVC codec
- Concatenation produced zero output frames.
- Video has no decodable frame
- Failed to delete video
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/10e7db788f2b5c94.
Report an issue: GitHub.