koala73/worldmonitor · error · TypeError
Physical divergence snapshot has an invalid envelope
Error message
Physical divergence snapshot has an invalid envelope
What it means
normalizePhysicalDivergenceSnapshot() first coerces the input to an object, validates the methodology version, then requires evaluatedAt to be a valid ISO instant and readings/transitions to be arrays. If any of these envelope-level checks fail it throws this TypeError, rejecting the snapshot before per-reading validation even begins. It is the top-level shape gate for the stored dataset.
Source
Thrown at server/_shared/physical-divergence-snapshot.ts:443
/**
* A snapshot written under a methodology this build does not implement. Distinct from an
* unknown state: this is ordinary producer/consumer deploy skew (the Railway seeder and the
* Vercel API ship independently), so a read path should fail closed with a reason rather
* than 500 for the length of the rollout window.
*/
export function isUnsupportedPhysicalDivergenceMethodology(error: unknown): boolean {
return error instanceof Error
&& error.message.startsWith('Unsupported physical divergence methodology:');
}
export function normalizePhysicalDivergenceSnapshot(
value: unknown,
nowMs = Date.now(),
): PhysicalDivergenceRawSnapshot {
const raw = object(value);
methodology(raw.methodologyVersion);
if (!isoInstant(raw.evaluatedAt) || !Array.isArray(raw.readings) || !Array.isArray(raw.transitions)) {
throw new TypeError('Physical divergence snapshot has an invalid envelope');
}
const storedReadings = raw.readings.map(reading);
if (
storedReadings.length !== PHYSICAL_DIVERGENCE_METALS.length
|| new Set(storedReadings.map((entry) => entry.metal)).size !== PHYSICAL_DIVERGENCE_METALS.length
) throw new TypeError('Physical divergence snapshot must contain gold and silver readings');
validateStoredComposite(raw.composite, storedReadings);
const readings = applyFreshness(storedReadings, nowMs);
return {
readings,
composite: buildPhysicalStressComposite(readings),
evaluatedAt: raw.evaluatedAt,
methodologyVersion: PHYSICAL_DIVERGENCE_METHODOLOGY_VERSION,
transitions: raw.transitions.map(transition),
};
}
View on GitHub (pinned to 9361220cc0)
Solutions
- Inspect the actual stored value at the snapshot cache key; purge the corrupt entry and let it regenerate from live data.
- Ensure the writer stores the parsed object (not JSON.stringify'd twice) with evaluatedAt as an ISO instant and readings/transitions arrays.
- If an error/empty response can be cached, guard the writer to only cache successfully normalized snapshots.
- Version the cache key with the methodology/snapshot schema version so old shapes are never re-read by new code.
Example fix
// before cache.set(key, JSON.stringify(snapshot)); // later read as string normalizePhysicalDivergenceSnapshot(raw); // throws: not an object // after const value = JSON.parse(raw); // parse once at the boundary normalizePhysicalDivergenceSnapshot(value);
Defensive patterns
Strategy: type-guard
Validate before calling
function looksLikeDivergenceEnvelope(v: unknown): boolean {
return !!v && typeof v === 'object'
&& typeof (v as any).evaluatedAt === 'string' && !Number.isNaN(Date.parse((v as any).evaluatedAt))
&& Array.isArray((v as any).readings) && Array.isArray((v as any).transitions);
}
if (!looksLikeDivergenceEnvelope(cached)) await refreshFromSource(); Type guard
function isDivergenceEnvelope(v: unknown): v is { evaluatedAt: string; readings: unknown[]; transitions: unknown[]; methodologyVersion: string } {
return !!v && typeof v === 'object'
&& typeof (v as any).evaluatedAt === 'string' && !Number.isNaN(Date.parse((v as any).evaluatedAt))
&& Array.isArray((v as any).readings) && Array.isArray((v as any).transitions);
} Try / catch
try {
const snapshot = normalizePhysicalDivergenceSnapshot(raw, Date.now());
} catch (err) {
if (err instanceof TypeError && err.message.includes('invalid envelope')) {
await cache.delete(key); // purge corrupt entry
snapshot = await fetchAndStoreFresh();
} else throw err;
} Prevention
- Parse JSON once at the cache boundary; never store double-stringified values.
- Only cache successfully normalized snapshots — never raw upstream/error payloads.
- Version cache keys with the snapshot schema/methodology version.
- Validate evaluatedAt with a strict ISO-instant check before writing.
When it happens
Trigger: getPhysicalDivergenceIndex / normalizePhysicalDivergenceDataset receiving cached or fetched data where evaluatedAt is missing/malformed (not an ISO 8601 instant), readings or transitions is not an array, or value isn't even an object — e.g. a JSON string was stored instead of a parsed object, or an error payload was cached.
Common situations: A cache entry holding `{ body: "..." }` wrapper JSON; double-stringified Redis values; an upstream error page cached in the snapshot key; schema drift after a producer change; empty/null cache reads passed straight through.
Related errors
- Physical divergence composite repeats a metal weight
- Physical divergence composite does not match its member read
- Physical divergence evaluation clock is invalid
- Physical divergence snapshot must contain gold and silver re
- get_intel_timeline requires at least one of domain ("conflic
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/9d7e0c264b14fc90.
Report an issue: GitHub.