koala73/worldmonitor · error · Error
${pagePath} heading leaks ISO code: ${text}
Error message
${pagePath} heading leaks ISO code: ${text} What it means
The crawlable-corpus build script validates that generated country/corpus pages do not leak machine ISO-3166 codes in visible headings. A heading (h1-h6) in the brief or main HTML matched MEANS_FOR_ISO_RE, meaning human-facing text contains an ISO code where a country name is expected. The build throws to stop a low-quality page from being published to the SEO corpus.
Solutions
- Find the page (pagePath is in the message) and inspect its heading source; identify which field supplied the heading text.
- Replace the ISO code with the country's display name in the data entry or template that renders the heading.
- If a name is missing upstream, add a code->name mapping fallback in the generator before rendering headings.
- Re-run the build to confirm the page passes the ISO-leak guard.
Example fix
// before
template `<h2>Security briefing: ${country.iso2}</h2>`
// after
template `<h2>Security briefing: ${country.displayName ?? NAME_BY_ISO[country.iso2]}</h2>` Defensive patterns
Strategy: validation
Validate before calling
const ISO_LEAK = /\b[A-Z]{2,3}\b/;
const text = heading.replace(/<[^>]+>/g, ' ').trim();
if (ISO_LEAK.test(text)) throw new Error(`heading leaks ISO code: ${text}`); Prevention
- Always render country display names, never ISO codes, in user-visible templates.
- Keep a code->name map as the single fallback source.
- Run the corpus validator locally before pushing.
When it happens
Trigger: Running the crawlable-corpus build (or its per-page validator) when a generated page's brief or main document contains an <h1>-<h6> whose stripped text matches the ISO-code detection regex, e.g. a heading like '<h2>Situation in DE</h2>'.
Common situations: Data templates that interpolate the country's ISO alpha-2/alpha-3 code instead of its display name; upstream data feeds returning codes in name fields; a newly added country lacking a localized display name so the template falls back to the code.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- needs a summary for the llms.txt Comparisons section
- ${pagePath} brief heading leaks an ISO-3166 alpha-2 code
- /accuracy/ meta description must be 155–160 chars (got ${len
- FAQ count must be 8-12, got ' + faqs.length
- H2 "' + merged.heading + '" has no following prose
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/d387c21bde6360db.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-crawlable-corpus.mjs:3590
throw new Error(`${pagePath} renders literal markdown emphasis in <main>`);
}
const brief = intelBriefHtml(html);
if (brief && sources !== undefined) {
// Check the rendered claim blocks as well as the input. A later formatter
// must not add an entity or change a citation after publish-time validation.
const claims = [...brief.matchAll(/<(p|li)\b([^>]*)>([\s\S]*?)<\/\1>/gi)]
.filter((match) => !/\bclass="source"/.test(match[2]))
.map((match) => corpusVisibleText(match[3]).replace(/&(amp|lt|gt|quot|#39);/g,
(entity) => ({ '&': '&', '<': '<', '>': '>', '"': '"', ''': "'" })[entity]));
const gap = briefCitationGroundingGap({ text: claims.join('\n'), sources });
if (gap) throw new Error(`${pagePath} brief has unsupported citation: ${gap}`);
}
const headingSource = brief ?? main;
const headingHits = [...headingSource.matchAll(/<h[1-6]\b[^>]*>([\s\S]*?)<\/h[1-6]>/gi)];
for (const hit of headingHits) {
const text = hit[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
if (MEANS_FOR_ISO_RE.test(text)) {
throw new Error(`${pagePath} heading leaks ISO code: ${text}`);
}
}
const briefLines = corpusMainHtml(brief ?? html)
.replace(/<br\b[^>]*>|<\/(?:p|h[1-6]|li|div)>/gi, '\n')
.replace(/<[^>]+>/g, ' ');
if (MEANS_FOR_ISO_RE.test(briefLines)) {
throw new Error(`${pagePath} brief heading leaks an ISO-3166 alpha-2 code`);
}
}
// A floor, not completeness. #7615 shipped this as
// `developmentsPageCount !== indexedCountryPageCount` -- every indexed country
// owed a dated development -- which no real capture can satisfy: the news cycle
// simply does not mention most countries. A fully keyed freeze on 2026-09-04
// covered 61 of 196 pages (54 headline-matched, 40 briefs, 18 timelines), so
// the gate rejected every snapshot the freeze could produce. That left the
// weekly refresh unable to publish and armed the
// MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS fuse against the whole corpus build.View on GitHub (pinned to 7d06c8633d)