koala73/worldmonitor · error · Error
${chokepoint.id}: ${field} contains unknown target ${id}
Error message
${chokepoint.id}: ${field} contains unknown target ${id} What it means
resolve() in buildChokepointPageLinks() maps each id from declaration.countryCodes or declaration.crisisSlugs through a lookup Map (countryByCode keyed by country.code, crisisBySlug keyed by crisis.slug). This throw fires when an id is absent from the target map, i.e. the declaration references a country code or crisis slug that does not exist in the countries/crises data supplied to the build. It blocks dangling references in generated chokepoint pages.
Solutions
- Fix the id in the chokepoint declaration to exactly match an existing country code (uppercase ISO-3166 alpha-2) or crisis slug from the data source.
- If the target was renamed, update every chokepoint declaration that references the old id in the same change.
- Verify the countries and crises arrays passed to buildChokepointPageLinks() are fully loaded and non-empty at call time.
- On failure, dump the available keys of countryByCode/crisisBySlug to spot casing or staleness mismatches quickly.
Example fix
// before crisisSlugs: ['red-sea'] // after crisisSlugs: ['red-sea-crisis']
Defensive patterns
Strategy: validation
Validate before calling
const knownCodes = new Set(countries.map((c) => c.code));
const knownSlugs = new Set(crises.map((c) => c.slug));
for (const id of content[chokepoint.id]?.countryCodes ?? []) {
if (!knownCodes.has(id)) throw new Error(`${chokepoint.id}: unknown country code ${id}`);
}
for (const slug of content[chokepoint.id]?.crisisSlugs ?? []) {
if (!knownSlugs.has(slug)) throw new Error(`${chokepoint.id}: unknown crisis slug ${slug}`);
} Try / catch
try {
buildChokepointPageLinks({ chokepoints, countries, crises, blogPostPaths, content });
} catch (err) {
const m = err.message.match(/contains unknown target (.+)$/);
if (m) console.error(`Unknown id "${m[1]}"; known codes: ${countries.map((c) => c.code).join(',')} slugs: ${crises.map((c) => c.slug).join(',')}`);
throw err;
} Prevention
- Reference ids only from the canonical country-code and crisis-slug lists.
- Update all referencing declarations in the same change that renames a crisis slug.
- Use exact uppercase ISO-3166 alpha-2 codes, never free-text names.
- Assert countries/crises arrays are non-empty before invoking the builder.
When it happens
Trigger: buildChokepointPageLinks() is called with a chokepoint whose countryCodes contains a code not present in countries[].code, or whose crisisSlugs contains a slug not present in crises[].slug — wrong casing ('us' vs 'US'), a renamed crisis slug, or an empty/partial countries/crises array passed by the caller.
Common situations: A crisis is renamed and re-slugified while a chokepoint declaration still references the old slug; a typo'd or lowercase ISO code; the caller passes an empty or filtered crises list so previously valid slugs vanish; the upstream data source temporarily omits entries.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- /accuracy/ meta description must be 155–160 chars (got ${len
- writeAccuracySection requires the canonical DataCatalog iden
- Missing comparison narrative for ' + page.slug
- FAQ count must be 8-12, got ' + faqs.length
- duplicate FAQ question: ' + question
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/f609e2763c59a859.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-crawlable-corpus.mjs:1385
const byCountryCode = new Map();
const byCrisisSlug = new Map();
for (const chokepoint of chokepoints) {
const declaration = content[chokepoint.id] || {};
const editorialLinks = declaration.editorialLinks ?? [];
if (!Array.isArray(editorialLinks)) throw new Error(`${chokepoint.id}: editorialLinks must be an array`);
const editorial = new Map();
for (const link of editorialLinks) {
if (!blogPostPaths.has(link?.href) || typeof link.label !== 'string' || !link.label.trim()) {
throw new Error(`${chokepoint.id}: editorialLinks requires a canonical blog post path and label: ${link?.href}`);
}
if (!editorial.has(link.href)) editorial.set(link.href, link);
}
const resolve = (field, targets, inverse) => {
const ids = declaration[field] ?? [];
if (!Array.isArray(ids)) throw new Error(`${chokepoint.id}: ${field} must be an array`);
return [...new Set(ids)].map((id) => {
const target = targets.get(id);
if (!target) throw new Error(`${chokepoint.id}: ${field} contains unknown target ${id}`);
const entries = inverse.get(id) || [];
entries.push(chokepoint);
inverse.set(id, entries);
return target;
});
};
byChokepointId.set(chokepoint.id, {
countries: resolve('countryCodes', countryByCode, byCountryCode),
crises: resolve('crisisSlugs', crisisBySlug, byCrisisSlug),
editorial: [...editorial.values()],
});
}
return { byChokepointId, byCountryCode, byCrisisSlug };
}
function renderRelatedChokepoints(chokepoints) {
if (!chokepoints.length) return '';
return ` <h2>Related chokepoint trackers</h2>View on GitHub (pinned to 7d06c8633d)