affaan-m/ECC · error · ValueError
cannot read plate
Error message
cannot read plate: {path} What it means
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.
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.
Example fix
// before
cv2.imread('assets/plate.png') # silently None if cwd differs
// after
from pathlib import Path
p = Path('assets/plate.png').resolve()
assert p.is_file(), f'missing plate: {p}'
im = cv2.imread(str(p), cv2.IMREAD_UNCHANGED) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
import cv2
def validate_plate(path):
p = Path(path)
if not p.is_file():
raise FileNotFoundError(path)
im = cv2.imread(str(p), cv2.IMREAD_UNCHANGED)
if im is None:
raise ValueError(f'undecodable image: {p}')
return p Type guard
def is_readable_image(path) -> bool:
from pathlib import Path
import cv2
p = Path(path)
return p.is_file() and cv2.imread(str(p), cv2.IMREAD_UNCHANGED) is not None Try / catch
try:
tighten(plate_path)
except ValueError as e:
if 'cannot read plate' in str(e):
logger.error('plate unreadable: %s', plate_path)
plate_path = fallback_plate Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9972ca29352d84da.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/taste/plates.py:225
def tighten(path: str | Path, dest: str | Path | None = None, pad: float = 0.06) -> Path:
"""Crop a plate to its own content, so the element fills the file.
A glow plate is mostly empty by construction - the selection keeps the top
few percent of pixels by energy, so a typical plate is 2-7% covered and
97% transparent black. Compositing that at full frame produces a small
bright dot floating in the middle of the shot, which reads as a sticker
rather than as light. Measured on the first cut: a plate covering 1.7% of
its own frame, screen-blended full-frame, was visible only as a coloured
blob near centre.
Cropping to the alpha bounding box means the caller controls the element's
size on screen by scaling, instead of inheriting whatever fraction of the
source frame the element happened to occupy.
"""
path = Path(path)
im = cv2.imread(str(path), cv2.IMREAD_UNCHANGED)
if im is None:
raise ValueError(f"cannot read plate: {path}")
alpha = im[..., 3] if im.shape[2] == 4 else im[..., :3].max(axis=2)
ys, xs = np.where(alpha > 12)
if len(ys) == 0:
return path
h, w = alpha.shape
py, px = int(h * pad), int(w * pad)
y0 = max(0, int(ys.min()) - py); y1 = min(h, int(ys.max()) + py + 1)
x0 = max(0, int(xs.min()) - px); x1 = min(w, int(xs.max()) + px + 1)
out = Path(dest) if dest else path.with_name(path.stem + "_tight.png")
out.parent.mkdir(parents=True, exist_ok=True)
cv2.imwrite(str(out), im[y0:y1, x0:x1])
return out
def plate_coverage(path: str | Path) -> float:
"""Share of the plate that is actually lit. Drives element-vs-wash choice."""
im = cv2.imread(str(path), cv2.IMREAD_UNCHANGED)
if im is None:View on GitHub (pinned to 8321021c54)