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

  1. 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.
  2. If the target was renamed, update every chokepoint declaration that references the old id in the same change.
  3. Verify the countries and crises arrays passed to buildChokepointPageLinks() are fully loaded and non-empty at call time.
  4. 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

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


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)