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

  1. Check os.path.exists(template_path) and that the working directory is what you expect.
  2. Print the absolute path and confirm the file is a supported format (PNG/JPEG/BGR-readable).
  3. Verify the file is committed to the repo and not gitignored.
  4. 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

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


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/a1b9d1f903abf402. Report an issue: GitHub.