{"record":{"id":"34d8f21a730f76e5","repo":"invoke-ai/InvokeAI","slug":"video-video-name-is-width-x-height-h-264-enco","errorCode":null,"errorMessage":"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.","messagePattern":"Video (.+?) is (.+?)x(.+?); H\\.264 encoding requires even dimensions\\. Re-encode or crop the source to even width and height first\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/invocations/video_frame_extract_range.py","lineNumber":50,"sourceCode":"from invokeai.app.invocations.primitives import VideoOutput\nfrom invokeai.app.services.session_processor.session_processor_common import CanceledException\nfrom invokeai.app.services.shared.invocation_context import InvocationContext\nfrom invokeai.app.util.video_encoding import make_mp4_writer\nfrom invokeai.app.util.video_thumbnails import decoder_frame_count, iter_video_frames, probe_video\n\n\nclass _FrameWriter(Protocol):\n    def append_data(self, frame: np.ndarray) -> None: ...\n\n\ndef _validate_even_dimensions(width: int, height: int, video_name: str) -> None:\n    \"\"\"Raises if the source dimensions can't be encoded as-is with libx264 + yuv420p.\n\n    We encode with ``macro_block_size=1`` to preserve the source dimensions exactly\n    (imageio's default of 16 silently rescales), which requires even width and height.\n    \"\"\"\n    if width % 2 or height % 2:\n        raise ValueError(\n            f\"Video {video_name} is {width}x{height}; H.264 encoding requires even dimensions. \"\n            \"Re-encode or crop the source to even width and height first.\"\n        )\n\n\ndef _write_frame_range(\n    frames: Iterator[np.ndarray],\n    writer: _FrameWriter,\n    start: int,\n    end: int,\n    is_canceled: Optional[Callable[[], bool]] = None,\n) -> int:\n    \"\"\"Streams frames[start..end] (inclusive) from a lazy decoder into the writer.\n\n    Frames are appended one at a time as they stream past — the full range is never\n    materialized in RAM. The upload cap admits files whose decoded frames would run to\n    tens of gigabytes, so peak memory here must stay one-frame-sized regardless of the\n    requested range. Decoding stops as soon as ``end`` has been written. Returns the","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/invocations/video_frame_extract_range.py#L32-L68","documentation":"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.","triggerScenarios":"invoke() -> _validate_even_dimensions(width, height) where width % 2 != 0 or height % 2 != 0, from probe_video of the source video.","commonSituations":"Sources cropped or scaled to odd sizes (e.g. 853x480); older footage with odd dimensions; programmatic crops computed without parity rounding.","solutions":["Crop or scale the source so width and height are even (e.g. scale=trunc(iw/2)*2:trunc(ih/2)*2)","Use ffmpeg to re-encode with even dimensions before extraction","Round crop boxes down to even values in your pipeline"],"exampleFix":"// before\nffmpeg -i in.mp4 -vf crop=853:480 out.mp4  # odd width 853\n// after\nffmpeg -i in.mp4 -vf \"crop=852:480\" out.mp4  # even dimensions","handlingStrategy":"validation","validationCode":"width, height, _, _ = probe_video(path)\nif width % 2 or height % 2:\n    raise ValueError(f'{path} has odd dimensions {width}x{height}; fix before range extract')","typeGuard":"def even_dims(width: int, height: int) -> bool:\n    return width % 2 == 0 and height % 2 == 0","tryCatchPattern":"try:\n    out = range_extract.invoke(context)\nexcept ValueError as e:\n    if 'even dimensions' in str(e):\n        run_ffmpeg(['-i', path, '-vf', 'crop=trunc(iw/2)*2:trunc(ih/2)*2', fixed_path])\n        out = rebuild(video=fixed_path).invoke(context)\n    else:\n        raise","preventionTips":["Round all crop/scale operations to even values","Normalize inputs with a standard filter chain at ingest","Add an even-dimension assertion in your pipeline tests"],"tags":["video","encoding","h264","validation"],"backgroundTag":"odd-video-dimensions","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}