{"record":{"id":"060d4118885f5031","repo":"invoke-ai/InvokeAI","slug":"decoded-frame-must-be-rgb-got-shape-frame-shape","errorCode":null,"errorMessage":"Decoded frame must be RGB; got shape {frame.shape}","messagePattern":"Decoded frame must be RGB; got shape (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"invokeai/app/util/video_decode_worker.py","lineNumber":71,"sourceCode":"    if sys.platform != \"linux\":\n        return\n    try:\n        import os\n        import resource\n\n        pages = int(Path(\"/proc/self/statm\").read_text().split()[0])\n        limit = pages * os.sysconf(\"SC_PAGE_SIZE\") + WORKER_MEMORY_HEADROOM_BYTES\n        _soft, hard = resource.getrlimit(resource.RLIMIT_AS)\n        if hard != resource.RLIM_INFINITY:\n            limit = min(limit, hard)\n        resource.setrlimit(resource.RLIMIT_AS, (limit, hard))\n    except (OSError, ValueError):\n        pass\n\n\ndef _validate_decoded_frame(frame: np.ndarray) -> None:\n    if frame.ndim != 3 or frame.shape[2] != 3:\n        raise ValueError(f\"Decoded frame must be RGB; got shape {frame.shape}\")\n    height, width = frame.shape[:2]\n    if height <= 0 or width <= 0 or height * width > MAX_FRAME_PIXELS:\n        raise ValueError(f\"Decoded frame dimensions {width}x{height} exceed the maximum decodable size\")\n\n\ndef _assert_decodable_dims(video_path: Path) -> None:\n    \"\"\"Refuses to decode frames from a video whose reported dimensions exceed the bound.\n\n    If the dimensions cannot be probed, decoding is refused because the parent's frame\n    record bound and PIL checks run only after the decoder has allocated the frame.\n    \"\"\"\n    try:\n        width, height, _duration, _fps = _probe(video_path)[:4]\n    except Exception as error:\n        raise ValueError(f\"Unable to validate video dimensions for {video_path}\") from error\n    if width <= 0 or height <= 0:\n        raise ValueError(f\"Video reports invalid dimensions {width}x{height}\")\n    if width * height > MAX_FRAME_PIXELS:","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/util/video_decode_worker.py#L53-L89","documentation":"_validate_decoded_frame checks that a decoded video frame is a 3-dimensional RGB ndarray (H, W, 3). OpenCV decodes frames as BGR with shape (H, W, 3), but frames arriving here are expected to have been converted to RGB; a grayscale, RGBA, or non-array frame fails this check. It is a defensive invariant check on the decode pipeline.","triggerScenarios":"A decoder returns a grayscale frame (ndim==2), an RGBA frame (shape[2]==4), or a non-RGB array passed to _validate_decoded_frame without cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) conversion.","commonSituations":"Forgetting cv2.COLOR_BGR2RGB conversion when switching between cv2 and imageio/PIL paths; videos with alpha channels or grayscale codecs; a decoder returning None or a differently-shaped array due to codec quirks.","solutions":["Convert BGR frames to RGB with cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) before validating","For grayscale videos, stack or cv2.cvtColor(cv2.COLOR_GRAY2RGB) before passing the frame","Check the decoder path producing the frame and ensure it always yields (H, W, 3) uint8 RGB arrays"],"exampleFix":"// before\n_validate_decoded_frame(frame_bgr)\n\n// after\nframe_rgb = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)\n_validate_decoded_frame(frame_rgb)","handlingStrategy":"validation","validationCode":"def is_rgb_frame(f) -> bool:\n    return isinstance(f, np.ndarray) and f.ndim == 3 and f.shape[2] == 3","typeGuard":"def is_rgb_frame(f: object) -> bool:\n    return isinstance(f, np.ndarray) and f.ndim == 3 and f.shape[2] == 3","tryCatchPattern":"try:\n    _validate_decoded_frame(frame)\nexcept ValueError as e:\n    if \"must be RGB\" in str(e):\n        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n        _validate_decoded_frame(frame)\n    else:\n        raise","preventionTips":["Always convert BGR to RGB immediately after cv2.VideoCapture().read()","Normalize grayscale/alpha frames to RGB before the pipeline","Keep frame arrays uint8 (H, W, 3) end-to-end","Add a shape assertion at decoder boundaries"],"tags":["opencv","video","numpy","color-space"],"backgroundTag":"invalid-frame-shape","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}