{"record":{"id":"9972ca29352d84da","repo":"affaan-m/ECC","slug":"cannot-read-plate-path","errorCode":null,"errorMessage":"cannot read plate: {path}","messagePattern":"cannot read plate: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/taste/plates.py","lineNumber":225,"sourceCode":"def tighten(path: str | Path, dest: str | Path | None = None, pad: float = 0.06) -> Path:\n    \"\"\"Crop a plate to its own content, so the element fills the file.\n\n    A glow plate is mostly empty by construction - the selection keeps the top\n    few percent of pixels by energy, so a typical plate is 2-7% covered and\n    97% transparent black. Compositing that at full frame produces a small\n    bright dot floating in the middle of the shot, which reads as a sticker\n    rather than as light. Measured on the first cut: a plate covering 1.7% of\n    its own frame, screen-blended full-frame, was visible only as a coloured\n    blob near centre.\n\n    Cropping to the alpha bounding box means the caller controls the element's\n    size on screen by scaling, instead of inheriting whatever fraction of the\n    source frame the element happened to occupy.\n    \"\"\"\n    path = Path(path)\n    im = cv2.imread(str(path), cv2.IMREAD_UNCHANGED)\n    if im is None:\n        raise ValueError(f\"cannot read plate: {path}\")\n    alpha = im[..., 3] if im.shape[2] == 4 else im[..., :3].max(axis=2)\n    ys, xs = np.where(alpha > 12)\n    if len(ys) == 0:\n        return path\n    h, w = alpha.shape\n    py, px = int(h * pad), int(w * pad)\n    y0 = max(0, int(ys.min()) - py); y1 = min(h, int(ys.max()) + py + 1)\n    x0 = max(0, int(xs.min()) - px); x1 = min(w, int(xs.max()) + px + 1)\n    out = Path(dest) if dest else path.with_name(path.stem + \"_tight.png\")\n    out.parent.mkdir(parents=True, exist_ok=True)\n    cv2.imwrite(str(out), im[y0:y1, x0:x1])\n    return out\n\n\ndef plate_coverage(path: str | Path) -> float:\n    \"\"\"Share of the plate that is actually lit. Drives element-vs-wash choice.\"\"\"\n    im = cv2.imread(str(path), cv2.IMREAD_UNCHANGED)\n    if im is None:","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/taste/plates.py#L207-L243","documentation":"plates.py raises ValueError('cannot read plate: {path}') when OpenCV's cv2.imread returns None, meaning the image file could not be loaded or decoded. The library expects an image file with an alpha channel (RGBA) or opaque content to crop/scale. This guards downstream code from operating on an empty array.","triggerScenarios":"Calling the plate-loading function (RAISED IN tighten) with a path that does not exist, is a directory, has an unsupported/corrupt image format, or a non-ASCII/permission-blocked path so cv2.imread returns None.","commonSituations":"Typo in file path; file was deleted or moved after being referenced in config; image saved without an extension OpenCV recognizes; relative path resolved from the wrong working directory; corrupted download.","solutions":["Verify the file exists at the exact path and print the resolved absolute path (Path(path).resolve()) before loading.","Open the image with PIL to confirm it is decodable; if PIL reads it but cv2 does not, re-save/re-encode it as PNG.","Fix the working-directory-relative path or pass an absolute path.","Check file permissions and that the path is not a directory."],"exampleFix":"// before\ncv2.imread('assets/plate.png')  # silently None if cwd differs\n// after\nfrom pathlib import Path\np = Path('assets/plate.png').resolve()\nassert p.is_file(), f'missing plate: {p}'\nim = cv2.imread(str(p), cv2.IMREAD_UNCHANGED)","handlingStrategy":"validation","validationCode":"from pathlib import Path\nimport cv2\ndef validate_plate(path):\n    p = Path(path)\n    if not p.is_file():\n        raise FileNotFoundError(path)\n    im = cv2.imread(str(p), cv2.IMREAD_UNCHANGED)\n    if im is None:\n        raise ValueError(f'undecodable image: {p}')\n    return p","typeGuard":"def is_readable_image(path) -> bool:\n    from pathlib import Path\n    import cv2\n    p = Path(path)\n    return p.is_file() and cv2.imread(str(p), cv2.IMREAD_UNCHANGED) is not None","tryCatchPattern":"try:\n    tighten(plate_path)\nexcept ValueError as e:\n    if 'cannot read plate' in str(e):\n        logger.error('plate unreadable: %s', plate_path)\n        plate_path = fallback_plate","preventionTips":["Resolve to absolute paths before passing media files","Verify files exist after downloads/copies before processing","Use PNG for plates to guarantee alpha channel support","Check cv2 build supports the image format in constrained environments"],"tags":["file-io","opencv","image"],"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"}