koala73/worldmonitor · error

${relativePath} is ${Math.round(ageDays)} days old (max ${MA

Error message

${relativePath} is ${Math.round(ageDays)} days old (max ${MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS}); run `npm run freeze:crawlable-live-pulse` to republish current values

What it means

resolveLatestLivePulseSnapshotPath enforces snapshot freshness: livePulseSnapshotAgeDays(capturedAt) must not exceed MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS. An expired snapshot makes every downstream claim stale, so the build throws '<relativePath> is N days old (max M); run `npm run freeze:crawlable-live-pulse` to republish current values'.

Solutions

  1. Run `npm run freeze:crawlable-live-pulse` to republish a current snapshot, then rebuild.
  2. Ensure the freeze step runs as part of CI/build on every deploy.
  3. Verify system date/timezone are correct if age looks wrong for a fresh snapshot.
  4. If intentionally working offline, adjust MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS only as a deliberate, reviewed policy change.

Example fix

// CI before
- npm run build:crawlable-corpus
// after
- npm run freeze:crawlable-live-pulse
- npm run build:crawlable-corpus
Defensive patterns

Strategy: retry

Validate before calling

const ageDays = (Date.now() - Date.parse(snapshot.capturedAt + 'T00:00:00Z')) / 86400000;
if (Math.round(ageDays) > MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS) console.warn(`snapshot ${snapshot.capturedAt} is stale; re-freeze before build`);

Try / catch

try {
  const path = resolveLatestLivePulseSnapshotPath();
} catch (err) {
  if (err.message.includes('days old (max')) {
    execSync('npm run freeze:crawlable-live-pulse', { stdio: 'inherit' });
    // retry once after re-freezing
  } else throw err;
}

Prevention

When it happens

Trigger: Building the crawlable corpus when the latest frozen live-pulse snapshot's capturedAt is more than MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS days before today's date.

Common situations: CI running after a weekend/holiday with no re-freeze; the freeze step skipped in the release pipeline; system clock or timezone skew inflating age; snapshot pinned to an old file whose capturedAt never updates.

Related errors


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

Appendix: source

Thrown at scripts/build-crawlable-corpus.mjs:481

    .sort((a, b) => b.match[1].localeCompare(a.match[1]));
  if (candidates.length === 0) {
    throw new Error(`No crawlable live-pulse snapshot found in ${RESILIENCE_SNAPSHOT_DIR}`);
  }

  const [{ filename, match }] = candidates;
  const relativePath = join(RESILIENCE_SNAPSHOT_DIR, filename);
  const snapshot = readJson(rootDir, relativePath);
  if (snapshot.capturedAt !== match[1]) {
    throw new Error(
      `${relativePath} filename date ${match[1]} does not match capturedAt ${snapshot.capturedAt}`,
    );
  }
  if (!snapshot.countries || !snapshot.chokepoints || !snapshot.crises || !snapshot.signalConvergence) {
    throw new Error(`${relativePath} is missing required live-pulse sections`);
  }
  const ageDays = livePulseSnapshotAgeDays(snapshot.capturedAt);
  if (ageDays > MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS) {
    throw new Error(
      `${relativePath} is ${Math.round(ageDays)} days old (max ${MAX_LIVE_PULSE_SNAPSHOT_AGE_DAYS}); `
      + 'run `npm run freeze:crawlable-live-pulse` to republish current values',
    );
  }
  return relativePath;
}

function formatStaticDateTime(iso) {
  const timestamp = Date.parse(iso);
  if (!Number.isFinite(timestamp)) return String(iso || '');
  return new Intl.DateTimeFormat('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
    timeZone: 'UTC',
    timeZoneName: 'short',

View on GitHub (pinned to 7d06c8633d)