koala73/worldmonitor · error

needs a World Monitor measurement explanation

Error message

 needs a World Monitor measurement explanation

What it means

After validating the snapshot date, renderMeasurement looks up COMPARISON_MEASUREMENTS[slug] for the page's 'How World Monitor measures this' paragraphs. Every comparison slug must have a measurement explanation; if the map has no entry (or an empty array), the build throws '<slug> needs a World Monitor measurement explanation'.

Solutions

  1. Add a COMPARISON_MEASUREMENTS entry keyed by the exact slug with at least one paragraph string.
  2. If the slug was renamed, rename the COMPARISON_MEASUREMENTS key to match the seed slug.
  3. Restore the deleted/emptied measurement paragraphs for that slug.

Example fix

// before
const COMPARISON_MEASUREMENTS = {
  'chokepoint-monitoring-tools': [...],
};
// after
const COMPARISON_MEASUREMENTS = {
  'chokepoint-monitoring-tools': [...],
  'country-instability-index-alternatives': [
    'World Monitor computes the Country Instability Index from ...',
  ],
};
Defensive patterns

Strategy: validation

Validate before calling

const missing = COMPARISON_PAGE_SEEDS.filter((s) => !(COMPARISON_MEASUREMENTS[s.slug]?.length));
if (missing.length) throw new Error(`slugs missing measurement prose: ${missing.map((s) => s.slug).join(', ')}`);

Prevention

When it happens

Trigger: Adding a new slug to COMPARISON_PAGE_SEEDS without adding a matching key in COMPARISON_MEASUREMENTS, or an entry whose value is [] — renderMeasurement then finds paragraphs?.length falsy.

Common situations: New comparison page added; slug renamed in the seeds but not in COMPARISON_MEASUREMENTS (typo or rebrand); measurement content removed pending rewrite, leaving an empty array.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/8cde76ec1542f1a1. Report an issue: GitHub.

Appendix: source

Thrown at scripts/build-comparison-pages.mjs:583

    '@type': 'WebPage',
    '@id': url + '#webpage',
    name,
    description,
    url,
    inLanguage: 'en-US',
    dateModified: lastmod,
    isPartOf: { '@id': new URL('/#website', baseUrl).href },
    breadcrumb: { '@id': url + '#breadcrumb' },
    mainEntity: { '@id': faqId },
  };
}

function renderMeasurement(slug, snapshotDate, escapeHtml) {
  if (!/^\d{4}-\d{2}-\d{2}$/.test(snapshotDate ?? '')) {
    throw new Error('Comparison measurement requires the captured snapshot date');
  }
  const paragraphs = COMPARISON_MEASUREMENTS[slug];
  if (!paragraphs?.length) throw new Error(slug + ' needs a World Monitor measurement explanation');
  const maritime = slug === 'chokepoint-monitoring-tools';
  const snapshotPath = maritime ? '/chokepoints/status.json' : '/country-instability-index/cii-ranking.json';
  return [
    '      <h2>How World Monitor measures this</h2>',
    ...renderParagraphs(paragraphs, escapeHtml),
    '      <p>Coverage: the <a href="/sources/">source catalog</a> lists ' + escapeHtml(formatCount(WORLD_MONITOR_PROVIDER_COUNT)) + ' active providers across the product, not per metric. Availability varies by source and location.</p>',
    '      <p data-measurement-snapshot><a href="' + snapshotPath + '">Published ' + (maritime ? 'chokepoint status' : 'country instability') + ' snapshot</a>, captured <time datetime="' + escapeHtml(snapshotDate) + '">' + escapeHtml(snapshotDate) + '</time>. This reference remains dated when live values change.</p>',
  ];
}

function renderComparePage(page, { tpl, baseUrl, lastmod, snapshotDate }) {
  const { escapeHtml, breadcrumbLd, pageDocument } = tpl;
  const pageUrl = new URL(page.path, baseUrl).href;
  const description = page.metaDescription ?? (page.h1
    + ' - ' + page.claim
    + '. Full comparison matrix, honest concessions, and FAQs.');
  assertMetaDescription(description, page.slug);

View on GitHub (pinned to 7d06c8633d)