affaan-m/ECC · error · RuntimeError
Template unreadable: {template_path}
Error message
Template unreadable: {template_path} What it means
A RuntimeError raised by debug_match() when cv2.imread(template_path) returns None, meaning OpenCV could not read the image file. This is a diagnosis-only helper used while calibrating the confidence threshold. cv2.imread returns None (rather than raising) on failure, so the guard is mandatory.
Source
Thrown at skills/windows-desktop-e2e/SKILL.md:808
3. **Record the scale alongside each artefact.** On capture, write `GetDpiForWindow(hwnd) / 96` to `artifacts/<test>/metadata.json` — postmortems become obvious instead of guess-work.
> Process-level DPI awareness (`SetProcessDpiAwarenessContext`) **can conflict with Qt's own DPI handling** when the app under test is Qt-based. Prefer "same-scale templates + CI pin" over flipping process-wide DPI mode in fixtures.
### Debugging Match Confidence
When tuning the `confidence` threshold, the only sane workflow is to **see** where the match landed. The helper below is diagnosis-only — do not call it from test code.
```python
def debug_match(template_path, out="artifacts/match_debug.png", confidence=0.85):
"""Diagnosis-only. Draw the best-match rectangle + score back on the current screen.
NOT for production tests — use when calibrating confidence or chasing false matches.
"""
import os, cv2, pyautogui, numpy as np
screen = np.array(pyautogui.screenshot())[:, :, ::-1]
tpl = cv2.imread(template_path)
if tpl is None:
raise RuntimeError(f"Template unreadable: {template_path}")
res = cv2.matchTemplate(screen, tpl, cv2.TM_CCOEFF_NORMED)
_, mv, _, ml = cv2.minMaxLoc(res)
h, w = tpl.shape[:2]
colour = (0, 255, 0) if mv >= confidence else (0, 0, 255) # green pass / red fail
cv2.rectangle(screen, ml, (ml[0]+w, ml[1]+h), colour, 2)
cv2.putText(screen, f"score={mv:.3f} thr={confidence}",
(ml[0], max(20, ml[1]-6)),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, colour, 2)
os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
cv2.imwrite(out, screen)
return mv
```
**Use sparingly** — image matching breaks on DPI changes, theme switches, and partial occlusion.
Always try UIA first; fall back to screenshots only for genuinely unreachable controls.
## Anti-Patterns
View on GitHub (pinned to 01e15490f0)
Solutions
- Check os.path.exists(template_path) and that the working directory is what you expect.
- Print the absolute path and confirm the file is a supported format (PNG/JPEG/BGR-readable).
- Verify the file is committed to the repo and not gitignored.
- Open the file in an image editor to confirm it is not corrupt; re-export as 8-bit sRGB PNG if needed.
Example fix
# before
tpl = cv2.imread(template_path)
if tpl is None:
raise RuntimeError(f"Template unreadable: {template_path}")
# after: distinguish missing-file from unreadable
import os
if not os.path.exists(template_path):
raise FileNotFoundError(f"Template missing: {os.path.abspath(template_path)}")
tpl = cv2.imread(template_path)
if tpl is None:
raise RuntimeError(f"Template unreadable or unsupported format: {template_path}") Defensive patterns
Strategy: validation
Validate before calling
import os
def template_readable(path) -> bool:
if not os.path.exists(path):
return False
import cv2
return cv2.imread(path) is not None
if not template_readable(template_path):
raise FileNotFoundError(f"template missing or unreadable: {os.path.abspath(template_path)}") Type guard
null
Try / catch
import os, cv2
if not os.path.exists(template_path):
raise FileNotFoundError(template_path)
tpl = cv2.imread(template_path)
if tpl is None:
raise RuntimeError(f"Template unreadable: {template_path}") Prevention
- Resolve template paths to absolute paths relative to the test file.
- Commit templates to the repo and verify they are not gitignored.
- Re-export templates as 8-bit sRGB PNG if OpenCV cannot decode them.
When it happens
Trigger: Calling debug_match(template_path) with a path that does not exist, is not an image, uses an unsupported format, or is unreadable due to permissions. cv2.imread silently returns None for all of these.
Common situations: Relative path resolved against the wrong working directory; template was never committed or was gitignored; file is .png.png due to a double extension; the image is a CMYK JPEG or 16-bit PNG that OpenCV cannot decode; permissions denied in CI.
Related errors
- Image not found on screen: {template_path}
- Condition not met within {timeout}s
- Multiple ECC repo roots detected: ${uniqueRepoRoots.join(',
- TypeScript compiler not found. Install root dev dependencies
- Missing value for --family
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/a1b9d1f903abf402.
Report an issue: GitHub.