koala73/worldmonitor · error · Error
Compact health pending must be an object
Error message
Compact health pending must be an object
What it means
Within validateCompactHealthPayload, if the compact health object carries a `pending` key it must be a non-null, non-array object whose values are entry objects. This check throws when `pending` is present but is null, an array, or a primitive, preventing downstream Object.values iteration from failing or silently mis-measuring pending seeds.
Solutions
- Fix the health endpoint/serializer to omit `pending` when empty or emit it as a keyed object
- If pending is now a list by design, update validateCompactHealthPayload and its consumers to the new shape
- Correct test fixtures/mocks to use an object map for pending
- Guard at the producer side: only include `pending` when it is a populated object
Example fix
// before
{"status":"HEALTHY","pending":null}
// after
{"status":"HEALTHY"} Defensive patterns
Strategy: type-guard
Validate before calling
if ('pending' in payload && (payload.pending === null || typeof payload.pending !== 'object' || Array.isArray(payload.pending))) throw new Error('pending must be a keyed object when present'); Type guard
const hasValidPending = (p) => !('pending' in p) || (p.pending !== null && typeof p.pending === 'object' && !Array.isArray(p.pending)); Try / catch
try {
validateCompactHealthPayload(payload);
} catch (e) {
if (e.message === 'Compact health pending must be an object') {
console.error('pending shape drifted from the compact health contract');
} else throw e;
} Prevention
- Omit the pending key entirely when there are no pending seeds
- Never serialize pending as null or an array
- Keep worker and checker deployed from the same contract/schema
- Add fixtures tests asserting pending's object shape
When it happens
Trigger: Health endpoint emitting `pending: null` (serialization of undefined), `pending: []` (array instead of keyed map), or `pending: "none"`; caller constructing the payload manually with a wrong-shaped pending field.
Common situations: API change where pending became a list of objects; a stub/mock fixture using an array; JSON produced by code that sets pending to null when empty instead of omitting the key.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Compact health payload must be an object
- Compact health pending entries must be objects
- Physical divergence snapshot must contain gold and silver re
- ${name} cronSchedule must be a string or null
- Convex embed key validation unavailable: invalid-payload
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/8f90266a8e72cb14.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/check-seed-freshness.mjs:20
import { readFileSync, writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { parseArgs } from 'node:util';
const DEFAULT_HEALTH_URL = 'https://api.worldmonitor.app/api/health?compact=1';
const BASELINE_URL = new URL('./seed-freshness-baseline.json', import.meta.url);
// api/health.js only serves a cached verdict for 60 seconds. Allow its maximum
// 20-second request timeout too, so a valid snapshot cannot be rejected solely
// because the response arrived at the end of the monitor's fetch window.
export const MAX_HEALTH_OBSERVATION_AGE_MS = 80 * 1000;
export function validateCompactHealthPayload(payload) {
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new Error('Compact health payload must be an object');
}
if (Object.hasOwn(payload, 'pending')) {
if (!payload.pending || typeof payload.pending !== 'object' || Array.isArray(payload.pending)) {
throw new Error('Compact health pending must be an object');
}
for (const entry of Object.values(payload.pending)) {
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
throw new Error('Compact health pending entries must be objects');
}
}
}
// Compact health omits `problems` entirely when every check is healthy.
if (payload.problems == null && payload.status === 'HEALTHY') return payload;
if (!payload.problems || typeof payload.problems !== 'object' || Array.isArray(payload.problems)) {
throw new Error('Compact health payload must contain a problems object');
}
return payload;
}
// The ONLY states being on-demand actually explains: nothing has requested the
// key yet, or the producer has not run for the first time. Absence is expected
// for an RPC-populated cache or a deployment-order bridge, so it must not page.View on GitHub (pinned to 7d06c8633d)