{"record":{"id":"e86b7d8b12fe4e6c","repo":"koala73/worldmonitor","slug":"report-report-id-role-id-has-no-valid-route-in-the","errorCode":null,"errorMessage":"Report ${report.id}: ${role} ${id} has no valid route in the chokepoint registry","messagePattern":"Report (.+?): (.+?) (.+?) has no valid route in the chokepoint registry","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/build-research-reports.mjs","lineNumber":718,"sourceCode":"  tpl,\n  baseUrl,\n  lastmod,\n  chokepointSlugById,\n  dataCatalog,\n  includedInDataCatalog,\n}) {\n  const { escapeHtml, absoluteUrl, breadcrumbLd, withUtmSource, pageDocument } = tpl;\n  const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;\n  if (!SLUG_PATTERN.test(report.slug) || !SLUG_PATTERN.test(report.id)) {\n    throw new Error(`Report slug/id must match ${SLUG_PATTERN}: ${report.slug} / ${report.id}`);\n  }\n  for (const [role, ids] of [\n    ['focusChokepointId', [report.focusChokepointId]],\n    ['contextChokepointId', report.contextChokepointIds],\n  ]) {\n    for (const id of ids) {\n      if (!SLUG_PATTERN.test(chokepointSlugById.get(id) ?? '')) {\n        throw new Error(`Report ${report.id}: ${role} ${id} has no valid route in the chokepoint registry`);\n      }\n    }\n  }\n  const chokepointSlug = chokepointSlugById.get(report.focusChokepointId);\n  const path = `/research/${report.slug}/`;\n  const canonical = absoluteUrl(baseUrl, path);\n  const focus = snapshot.chokepoints[report.focusChokepointId];\n  const resolve = (text) => resolveMetricTokens(escapeHtml(text), metrics, escapeHtml);\n  const m = (id) => {\n    const metric = metrics.get(id);\n    if (!metric) throw new Error(`Unknown metric: ${id}`);\n    return metric;\n  };\n  // Plain-text description for surfaces that cannot carry <data> markup; the\n  // definition writes it with {{m:...}} tokens so its numbers cannot drift\n  // from the computed metrics.\n  const description = resolvePlainMetricTokens(report.description, metrics);\n  const partialMonth = focus.observationEnd.slice(0, 7);","sourceCodeStart":700,"sourceCodeEnd":736,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/build-research-reports.mjs#L700-L736","documentation":"After slug validation, the research-reports builder resolves each referenced chokepoint (focus and context) through the chokepoint registry to build its route. If a referenced chokepoint id has no entry whose slug passes SLUG_PATTERN, the link would be dead, so the build throws identifying the report, role, and id.","triggerScenarios":"A report's focusChokepointId or an entry in contextChokepointIds references an id absent from chokepointSlugById (typo, deleted chokepoint, registry not yet regenerated) when the reports build runs.","commonSituations":"Renaming/removing a chokepoint in the registry without updating reports that reference it; typos in report front-matter ids; registry built from a different data revision than the reports.","solutions":["Fix the report's focusChokepointId / contextChokepointIds to reference an id that exists in the chokepoint registry.","If the chokepoint was intentionally removed, remove or replace the reference in the report data.","Regenerate/rebuild the chokepoint registry so chokepointSlugById is current before the reports build.","Consider a data-level referential-integrity check so bad ids fail at authoring time."],"exampleFix":"// before\n{ id: 'hormuz-strait', contextChokepointIds: ['suez-canal-old'] }\n// after\n{ id: 'hormuz-strait', contextChokepointIds: ['suez-canal'] }","handlingStrategy":"validation","validationCode":"const missing = [report.focusChokepointId, ...report.contextChokepointIds]\n  .filter((id) => !chokepointSlugById.has(id));\nif (missing.length) throw new Error(`unknown chokepoint ids: ${missing.join(', ')}`);","typeGuard":null,"tryCatchPattern":"try { renderReport(report); } catch (e) { console.error(e.message); /* fix registry or report refs */ }","preventionTips":["Reference chokepoints only via ids generated from the registry.","Run a referential-integrity lint over report data before builds.","When removing a chokepoint, grep reports for its id first."],"tags":["build","referential-integrity","validation"],"backgroundTag":"entity-not-found","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}