invoke-ai/InvokeAI · error · ValueError

Video is x ; H.264 encoding requires even dimensions…

Error message

Video {video_name} is {width}x{height}; H.264 encoding requires even dimensions. Re-encode or crop the source to even width and height first.

What it means

Thrown by _validate_even_dimensions in the frame-range extraction/export path. Output is encoded with libx264 + yuv420p and macro_block_size=1 to preserve exact source dimensions, which requires even width and height. Odd dimensions would either fail or be silently rescaled by the encoder.

Solutions

  1. Crop or scale the source so width and height are even (e.g. scale=trunc(iw/2)*2:trunc(ih/2)*2)
  2. Use ffmpeg to re-encode with even dimensions before extraction
  3. Round crop boxes down to even values in your pipeline

Example fix

// before
ffmpeg -i in.mp4 -vf crop=853:480 out.mp4  # odd width 853
// after
ffmpeg -i in.mp4 -vf "crop=852:480" out.mp4  # even dimensions
Defensive patterns

Strategy: validation

Validate before calling

width, height, _, _ = probe_video(path)
if width % 2 or height % 2:
    raise ValueError(f'{path} has odd dimensions {width}x{height}; fix before range extract')

Type guard

def even_dims(width: int, height: int) -> bool:
    return width % 2 == 0 and height % 2 == 0

Try / catch

try:
    out = range_extract.invoke(context)
except ValueError as e:
    if 'even dimensions' in str(e):
        run_ffmpeg(['-i', path, '-vf', 'crop=trunc(iw/2)*2:trunc(ih/2)*2', fixed_path])
        out = rebuild(video=fixed_path).invoke(context)
    else:
        raise

Prevention

When it happens

Trigger: invoke() -> _validate_even_dimensions(width, height) where width % 2 != 0 or height % 2 != 0, from probe_video of the source video.

Common situations: Sources cropped or scaled to odd sizes (e.g. 853x480); older footage with odd dimensions; programmatic crops computed without parity rounding.

Related errors


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

Appendix: source

Thrown at invokeai/app/invocations/video_frame_extract_range.py:50

from invokeai.app.invocations.primitives import VideoOutput
from invokeai.app.services.session_processor.session_processor_common import CanceledException
from invokeai.app.services.shared.invocation_context import InvocationContext
from invokeai.app.util.video_encoding import make_mp4_writer
from invokeai.app.util.video_thumbnails import decoder_frame_count, iter_video_frames, probe_video


class _FrameWriter(Protocol):
    def append_data(self, frame: np.ndarray) -> None: ...


def _validate_even_dimensions(width: int, height: int, video_name: str) -> None:
    """Raises if the source dimensions can't be encoded as-is with libx264 + yuv420p.

    We encode with ``macro_block_size=1`` to preserve the source dimensions exactly
    (imageio's default of 16 silently rescales), which requires even width and height.
    """
    if width % 2 or height % 2:
        raise ValueError(
            f"Video {video_name} is {width}x{height}; H.264 encoding requires even dimensions. "
            "Re-encode or crop the source to even width and height first."
        )


def _write_frame_range(
    frames: Iterator[np.ndarray],
    writer: _FrameWriter,
    start: int,
    end: int,
    is_canceled: Optional[Callable[[], bool]] = None,
) -> int:
    """Streams frames[start..end] (inclusive) from a lazy decoder into the writer.

    Frames are appended one at a time as they stream past — the full range is never
    materialized in RAM. The upload cap admits files whose decoded frames would run to
    tens of gigabytes, so peak memory here must stay one-frame-sized regardless of the
    requested range. Decoding stops as soon as ``end`` has been written. Returns the

View on GitHub (pinned to 0b6a024f2f)