{"record":{"id":"939515c9a19ee5df","repo":"pbakaus/impeccable","slug":"font-match-no-region-id-ids-ids","errorCode":null,"errorMessage":"font-match: no region {id}; ids: {ids}\n","messagePattern":"font-match: no region (.+?); ids: (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/comp-verbs/src/font_match.rs","lineNumber":448,"sourceCode":"        io.err(\"usage: font-match.mjs --measure <text-region-id> | --rank <text-region-id> [--candidates \\\"Family:700,Family2:400,...\\\"] [--text \\\"...\\\"] [--transform uppercase] [--category sans,serif,display,handwriting,mono]\\n\");\n        return 1;\n    };\n    let Some(spec_val) = spec.as_mut() else {\n        io.err(&format!(\"font-match: no spec at {spec_path}; run comp-spec.mjs first\\n\"));\n        return 1;\n    };\n    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.","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/pbakaus/impeccable/blob/2bc2879276c1f321a53c4ca99d3371e411329b52/crates/comp-verbs/src/font_match.rs#L430-L466","documentation":"After loading the spec, `font-match.mjs` looks up the requested id in the spec's `regions` array. If no region with that id exists, it prints this message including a comma-separated list of all valid region ids, so the error doubles as a discovery aid. Exit code is 1 and no font measurement happens.","triggerScenarios":"Passing `--measure <id>` or `--rank <id>` where `<id>` is misspelled, was renamed in the spec, or was never defined; the spec has an empty or missing `regions` array (ids list prints empty); the id belongs to a different spec file than the one loaded via `--spec`.","commonSituations":"Guessing region ids instead of reading the spec; editing region ids in the spec JSON by hand after running font-match scripts; stale automation pinned to an old id after a re-measure; the spec regenerated with `--auto` produced different band ids than expected.","solutions":["Use an id from the `ids:` list printed in the error message.","Inspect the spec's `regions` array (`jq '.regions[].id' <spec>`) to see current ids.","Regenerate regions with `comp-spec --grid` / `--auto` if the region you need doesn't exist yet.","Point `--spec` at the correct spec file if the id lives in a different one."],"exampleFix":"// before\nnode font-match.mjs --measure hero\ndev\n// font-match: no region hero-title; ids: hero-title, nav-link\n// after\nnode font-match.mjs --measure hero-title","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nconst spec = JSON.parse(readFileSync(specPath, 'utf8'));\nconst ids = (spec.regions ?? []).map(r => r.id);\nif (!ids.includes(regionId)) {\n  throw new Error(`region \"${regionId}\" not in spec; available: ${ids.join(', ')}`);\n}","typeGuard":"function regionExists(spec, id) {\n  return Array.isArray(spec?.regions) && spec.regions.some(r => r?.id === id);\n}","tryCatchPattern":"try {\n  runFontMatch(['--measure', id]);\n} catch (e) {\n  if (String(e.stderr).startsWith('font-match: no region')) {\n    const ids = String(e.stderr).match(/ids: (.*)/)?.[1] ?? '';\n    console.warn(`Unknown id \"${id}\"; valid ids: ${ids}`);\n  } else throw e;\n}","preventionTips":["List region ids from the spec (`jq '.regions[].id' spec.json`) before invoking font-match.","Centralize region id constants instead of inlining strings in scripts.","Re-check ids after any spec regeneration — --auto band ids can change."],"tags":["cli","entity-not-found","identifier"],"backgroundTag":"entity-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"}