pbakaus/impeccable · error
font-match: cannot read {comp_file}: {e}
Error message
font-match: cannot read {comp_file}: {e}
What it means
Once the region is found, font-match loads the comp raster image named in the spec's `comp` field and crops the region pixels for font analysis. If `png_io::load_raster` fails (file missing, unreadable, not a valid PNG), the tool reports the failing path and the underlying cause with this message and exits 1.
Source
Thrown at crates/comp-verbs/src/font_match.rs:455
let region = spec_val
.get("regions")
.and_then(Value::as_array)
.and_then(|a| a.iter().find(|r| r.get("id").and_then(Value::as_str) == Some(id)))
.cloned();
let Some(region) = region else {
let ids = spec_val
.get("regions")
.and_then(Value::as_array)
.map(|a| a.iter().filter_map(|r| r.get("id").and_then(Value::as_str)).collect::<Vec<_>>().join(", "))
.unwrap_or_default();
io.err(&format!("font-match: no region {id}; ids: {ids}\n"));
return 1;
};
let comp_file = spec_val.get("comp").and_then(Value::as_str).unwrap_or("").to_string();
let comp = match png_io::load_raster(&resolve(io, &comp_file)) {
Ok((d, _)) => d.image,
Err(e) => {
io.err(&format!("font-match: cannot read {comp_file}: {e}\n"));
return 1;
}
};
let px = |k: &str| region.pointer(&format!("/px/{k}")).and_then(Value::as_f64).unwrap_or(0.0);
let (rx, ry, rw, rh) = (px("x"), px("y"), px("w"), px("h"));
let c = r::crop(&comp, rx, ry, rw, rh);
let fp = fingerprint(&c, &FpOpts::default());
let px_w = rw as i64;
let px_h = rh as i64;
let Some(fp) = fp else {
// No lettering: record the attempt and size by the box.
if let Some(reg) = region_mut(spec_val, id) {
let ty = reg.as_object_mut().and_then(|_| None::<()>);
let _ = ty;
let mut tmap = reg.get("type").and_then(|t| t.as_object()).cloned().unwrap_or_default();
tmap.insert("comp".into(), Value::Null);
tmap.insert("measuredAt".into(), json!(util::iso_now()));
tmap.insert("note".into(), json!("no separable lettering in the crop; size by the region box"));View on GitHub (pinned to 2bc2879276)
Solutions
- Restore or regenerate the comp PNG at the path in the spec's `comp` field (re-run the screenshot/comp-spec step).
- Check the recorded path: `jq -r '.comp' <spec>` and verify the file exists relative to your current directory.
- Run font-match from the same working directory used when the spec was created, or fix the stored path to be correct.
- Confirm the file is a valid, readable PNG (`file <path>`); replace it if corrupt.
Example fix
// before (spec.comp = "shot.png", file deleted) node font-match.mjs --measure hero-title // font-match: cannot read shot.png: No such file or directory // after node comp-spec.mjs --comp shot.png --auto # regenerates spec + ensures comp path node font-match.mjs --measure hero-title
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readFileSync } from 'node:fs';
const spec = JSON.parse(readFileSync(specPath, 'utf8'));
const compPath = spec.comp;
if (!compPath || !existsSync(compPath)) {
throw new Error(`comp image "${compPath}" missing — regenerate it before font-match`);
}
const magic = readFileSync(compPath).subarray(0, 8);
if (!magic.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
throw new Error(`${compPath} is not a valid PNG`);
} Type guard
function compIsReadable(spec) {
try {
const p = spec?.comp;
return typeof p === 'string' && p.length > 0 && existsSync(p) && statSync(p).size > 0;
} catch { return false; }
} Try / catch
try {
runFontMatch(args);
} catch (e) {
if (String(e.stderr).includes('cannot read')) {
const path = String(e.stderr).match(/cannot read ([^:]+):/)?.[1];
console.error(`Regenerate the comp image at ${path} (rerun screenshot/comp-spec)`);
process.exit(1);
} else throw e;
} Prevention
- Keep the comp PNG under version control or regenerate it in the same pipeline step as the spec.
- Never delete screenshots while their spec still references them.
- Run font-match from the directory where the spec was created so relative comp paths resolve.
When it happens
Trigger: The PNG recorded in the spec's `comp` field was deleted, moved, or renamed after comp-spec ran; the path is relative and font-match is run from a different working directory; the file exists but is corrupt or not a PNG; permissions prevent reading it.
Common situations: Cleaning up screenshots while keeping the spec; moving the project folder so relative comp paths break; a partial/failed download left a truncated PNG; committing the spec to git but ignoring the screenshot asset.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- {}
- embed-prompt: no such path {}
- embed-prompt: image file required
- {e} (dynamic error string from bundle::resolve_link_source)
- concept-seed: --candidate-count must be an integer from 5 to
AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08).
Data as JSON: /api/errors/99f2facb5867e47c.
Report an issue: GitHub.