{"record":{"id":"09cc8117a340dc86","repo":"affaan-m/ECC","slug":"cannot-read-overlay-image-image","errorCode":null,"errorMessage":"cannot read overlay image: {image}","messagePattern":"cannot read overlay image: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/taste/assemble.py","lineNumber":113,"sourceCode":"    the same mark in the same place every time.\n\n    ``screen`` is the default because plates are premultiplied against black,\n    so screen drops their blacks for free and no matte is needed.\n    \"\"\"\n    clip, image, dst = Path(clip), Path(image), Path(dst)\n    if width is None or height is None:\n        from . import frames as _fm\n        info = _fm.probe(clip)\n        width, height = info.width, info.height\n\n    # Resolve the element's pixel size here rather than in ffmpeg expressions.\n    # pad() rejects a negative offset and cannot pad to a size smaller than its\n    # input, so an element that lands oversized or off-frame kills the whole\n    # filtergraph - which it did on the first attempt.\n    import cv2 as _cv2\n    _im = _cv2.imread(str(image), _cv2.IMREAD_UNCHANGED)\n    if _im is None:\n        raise ValueError(f\"cannot read overlay image: {image}\")\n    ih0, iw0 = _im.shape[:2]\n    ew = max(2, int(width * max(0.02, min(1.0, scale))))\n    eh = max(2, int(ew * ih0 / max(1, iw0)))\n    if eh > height:  # fit tall elements to the frame instead of overflowing\n        eh = height\n        ew = max(2, int(eh * iw0 / max(1, ih0)))\n    ew, eh = min(ew, width), min(eh, height)\n    if isinstance(position, tuple):\n        px = int(width * position[0])\n        py = int(height * position[1])\n    else:\n        anchors = {\n            \"center\": (0.5, 0.5), \"top\": (0.5, 0.12), \"bottom\": (0.5, 0.88),\n            \"left\": (0.14, 0.5), \"right\": (0.86, 0.5),\n            \"topleft\": (0.16, 0.16), \"topright\": (0.84, 0.16),\n            \"bottomleft\": (0.16, 0.84), \"bottomright\": (0.84, 0.84),\n        }\n        ax, ay = anchors.get(position, (0.5, 0.5))","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/taste/assemble.py#L95-L131","documentation":"overlay() raises this ValueError when cv2.imread cannot load the overlay image, returning None. This guards the rest of the function (dimension computation and ffmpeg filtergraph construction) from crashing on an unreadable path. It means the path is wrong, the file is corrupt, or the format is unsupported by OpenCV.","triggerScenarios":"Calling overlay() with an image path that does not exist, is a directory, has an unsupported/undetectable extension, contains truncated/corrupt data, or uses characters/permissions that block reading — cv2.imread returns None and this error fires.","commonSituations":"Typo'd or relative path resolved from the wrong working directory; an SVG or other non-raster format OpenCV can't decode; an image downloaded incompletely; permission-restricted asset paths.","solutions":["Verify the image path exists and is a readable file (os.path.isfile) before calling overlay()","Use a raster format OpenCV supports (PNG/JPEG); convert SVG/HEIC assets to PNG first","Check file permissions on the image","Load the image yourself with cv2.imread first and confirm it is not None to catch the problem early"],"exampleFix":"// before\noverlay(frame_src, \"logo.svg\", ...)  # OpenCV cannot read SVG\n// after\noverlay(frame_src, \"logo.png\", ...)  # pre-converted raster image","handlingStrategy":"validation","validationCode":"from pathlib import Path\nimport cv2\n\ndef ensure_readable_overlay(image):\n    p = Path(image)\n    if not p.is_file():\n        raise FileNotFoundError(p)\n    if cv2.imread(str(p), cv2.IMREAD_UNCHANGED) is None:\n        raise ValueError(f\"unreadable/unsupported image: {p}\")","typeGuard":"def is_valid_image(path) -> bool:\n    import cv2\n    from pathlib import Path\n    p = Path(path)\n    return p.is_file() and cv2.imread(str(p), cv2.IMREAD_UNCHANGED) is not None","tryCatchPattern":"try:\n    overlay(src, image, ...)\nexcept ValueError as e:\n    if str(e).startswith(\"cannot read overlay image\"):\n        print(f\"bad overlay asset: {e}\")\n    raise","preventionTips":["Convert all overlay assets to PNG/JPEG before use","Use absolute paths or resolve relative to a known base directory","Check file existence and readability in a pre-flight step","Validate downloaded assets (file size > 0, decodable) before passing them in"],"tags":["opencv","file-io","image","validation"],"backgroundTag":"file-read-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}