{"record":{"id":"99f2facb5867e47c","repo":"pbakaus/impeccable","slug":"font-match-cannot-read-comp-file-e","errorCode":null,"errorMessage":"font-match: cannot read {comp_file}: {e}\n","messagePattern":"font-match: cannot read (.+?): (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/comp-verbs/src/font_match.rs","lineNumber":455,"sourceCode":"    let region = spec_val\n        .get(\"regions\")\n        .and_then(Value::as_array)\n        .and_then(|a| a.iter().find(|r| r.get(\"id\").and_then(Value::as_str) == Some(id)))\n        .cloned();\n    let Some(region) = region else {\n        let ids = spec_val\n            .get(\"regions\")\n            .and_then(Value::as_array)\n            .map(|a| a.iter().filter_map(|r| r.get(\"id\").and_then(Value::as_str)).collect::<Vec<_>>().join(\", \"))\n            .unwrap_or_default();\n        io.err(&format!(\"font-match: no region {id}; ids: {ids}\\n\"));\n        return 1;\n    };\n    let comp_file = spec_val.get(\"comp\").and_then(Value::as_str).unwrap_or(\"\").to_string();\n    let comp = match png_io::load_raster(&resolve(io, &comp_file)) {\n        Ok((d, _)) => d.image,\n        Err(e) => {\n            io.err(&format!(\"font-match: cannot read {comp_file}: {e}\\n\"));\n            return 1;\n        }\n    };\n    let px = |k: &str| region.pointer(&format!(\"/px/{k}\")).and_then(Value::as_f64).unwrap_or(0.0);\n    let (rx, ry, rw, rh) = (px(\"x\"), px(\"y\"), px(\"w\"), px(\"h\"));\n    let c = r::crop(&comp, rx, ry, rw, rh);\n    let fp = fingerprint(&c, &FpOpts::default());\n    let px_w = rw as i64;\n    let px_h = rh as i64;\n    let Some(fp) = fp else {\n        // No lettering: record the attempt and size by the box.\n        if let Some(reg) = region_mut(spec_val, id) {\n            let ty = reg.as_object_mut().and_then(|_| None::<()>);\n            let _ = ty;\n            let mut tmap = reg.get(\"type\").and_then(|t| t.as_object()).cloned().unwrap_or_default();\n            tmap.insert(\"comp\".into(), Value::Null);\n            tmap.insert(\"measuredAt\".into(), json!(util::iso_now()));\n            tmap.insert(\"note\".into(), json!(\"no separable lettering in the crop; size by the region box\"));","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/pbakaus/impeccable/blob/2bc2879276c1f321a53c4ca99d3371e411329b52/crates/comp-verbs/src/font_match.rs#L437-L473","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (spec.comp = \"shot.png\", file deleted)\nnode font-match.mjs --measure hero-title\n// font-match: cannot read shot.png: No such file or directory\n// after\nnode comp-spec.mjs --comp shot.png --auto   # regenerates spec + ensures comp path\nnode font-match.mjs --measure hero-title","handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from 'node:fs';\nconst spec = JSON.parse(readFileSync(specPath, 'utf8'));\nconst compPath = spec.comp;\nif (!compPath || !existsSync(compPath)) {\n  throw new Error(`comp image \"${compPath}\" missing — regenerate it before font-match`);\n}\nconst magic = readFileSync(compPath).subarray(0, 8);\nif (!magic.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {\n  throw new Error(`${compPath} is not a valid PNG`);\n}","typeGuard":"function compIsReadable(spec) {\n  try {\n    const p = spec?.comp;\n    return typeof p === 'string' && p.length > 0 && existsSync(p) && statSync(p).size > 0;\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  runFontMatch(args);\n} catch (e) {\n  if (String(e.stderr).includes('cannot read')) {\n    const path = String(e.stderr).match(/cannot read ([^:]+):/)?.[1];\n    console.error(`Regenerate the comp image at ${path} (rerun screenshot/comp-spec)`);\n    process.exit(1);\n  } else throw e;\n}","preventionTips":["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."],"tags":["cli","file-not-found","image"],"backgroundTag":"file-not-found","analyzedSha":"2bc2879276c1f321a53c4ca99d3371e411329b52","analyzedAt":"2026-09-08T04:51:14.109Z","contentChangedAt":"2026-09-08T04:51:14.109Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}