koala73/worldmonitor · error · Error
Compact health payload must be an object
Error message
Compact health payload must be an object
What it means
check-seed-freshness validates the compact health payload fetched from the monitor before inspecting seed freshness. validateCompactHealthPayload requires the payload to be a non-null, non-array object; anything else (null, undefined, a JSON array, a string/number) is rejected. This ensures downstream Object.values/Object.hasOwn checks operate on a real object shape.
Solutions
- Log/inspect the fetched payload and fix the fetch/parse step so it yields the compact health object
- Ensure the caller awaits response.json() and passes that parsed value, not raw text
- Check the health endpoint is returning the compact payload (correct URL/version) rather than an error body
- Wrap the call in a try/catch that reports the invalid payload type for diagnosis
Example fix
// before validateCompactHealthPayload(await res.text()); // after const payload = await res.json(); if (payload && !Array.isArray(payload)) validateCompactHealthPayload(payload);
Defensive patterns
Strategy: type-guard
Validate before calling
const payload = await res.json();
if (payload === null || typeof payload !== 'object' || Array.isArray(payload)) throw new Error('health endpoint did not return an object'); Type guard
const isCompactHealthPayload = (p) => p !== null && typeof p === 'object' && !Array.isArray(p);
Try / catch
try {
validateCompactHealthPayload(payload);
} catch (e) {
if (e.message === 'Compact health payload must be an object') {
console.error('Non-object payload from health endpoint; check fetch/parse and endpoint version');
} else throw e;
} Prevention
- Always parse the response with res.json() before validating
- Check the health endpoint URL/version returns the compact payload
- Return an error object (never null/array) from fetch wrappers
- Add a contract test asserting the endpoint's top-level shape
When it happens
Trigger: Calling validateCompactHealthPayload with the result of a fetch that returned null/undefined, a JSON array instead of an object, or a string (e.g. an HTML error page parsed loosely or raw text passed through).
Common situations: Health endpoint returned an error page or empty body that got JSON-parsed into something unexpected; API version change reshaped the response into an array; caller passed the raw response text instead of the parsed JSON object.
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 pending 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/48692978789b35ce.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/check-seed-freshness.mjs:16
#!/usr/bin/env node
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;
}View on GitHub (pinned to 7d06c8633d)