koala73/worldmonitor · error
Comparison measurement requires the captured snapshot date
Error message
Comparison measurement requires the captured snapshot date
What it means
renderMeasurement embeds a 'How World Monitor measures this' section with a snapshot date that must be an ISO YYYY-MM-DD string. The snapshot date anchors the measurement claims to a captured data date; if snapshotDate is missing, null, or not in the exact format, the build throws 'Comparison measurement requires the captured snapshot date'.
Solutions
- Pass the capturedAt value from the frozen live-pulse snapshot, formatted exactly YYYY-MM-DD.
- If you have a full timestamp, slice the date part: capturedAt.slice(0, 10) (valid only if it starts with YYYY-MM-DD).
- Check the caller/config supplying snapshotDate — a missing env/config value becomes undefined here.
Example fix
// before renderMeasurement(slug, snapshot.capturedAt, escapeHtml); // '2026-09-15T04:12:00Z' // after renderMeasurement(slug, snapshot.capturedAt.slice(0, 10), escapeHtml); // '2026-09-15'
Defensive patterns
Strategy: validation
Validate before calling
if (!/^\d{4}-\d{2}-\d{2}$/.test(snapshotDate ?? '')) throw new Error('snapshotDate must be YYYY-MM-DD'); Type guard
const isIsoDate = (v) => typeof v === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(v); Prevention
- Always slice full ISO timestamps to 10 chars before passing as snapshotDate.
- Store snapshot dates in config in plain YYYY-MM-DD form.
When it happens
Trigger: renderMeasurement invoked (directly or via page rendering) with snapshotDate undefined/null or a string failing /^\d{4}-\d{2}-\d{2}$/ — e.g. '2026/09/15', '2026-9-1', or a full ISO timestamp '2026-09-15T00:00:00Z'.
Common situations: A caller passes the whole snapshot object instead of its capturedAt field; a config file stores the date with slashes or a full timestamp; the date constant was removed during a refactor and undefined flows through.
Related errors
- start_date must be YYYY-MM-DD
- end_date must be YYYY-MM-DD
- is missing methodology prose
- profile "' + profile.name + '" has no prose
- needs a World Monitor measurement explanation
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/179ba01a3e0327e1.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-comparison-pages.mjs:580
function comparisonWebPageLd({ name, description, url, lastmod, faqId, baseUrl }) {
return {
'@context': 'https://schema.org',
'@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.claimView on GitHub (pinned to 7d06c8633d)