koala73/worldmonitor · error · Error
Cloudflare Radar ${source}: result.${field} is missing or no
Error message
Cloudflare Radar ${source}: result.${field} is missing or not an object What it means
requireRadarObject() validates that a Cloudflare Radar response result field is a plain object (e.g. Radar summary maps like traffic shares by country). It rejects null/undefined, non-objects, and arrays (arrays are not valid here even though typeof array === 'object'). The script fails hard rather than seeding empty summary data.
Solutions
- Inspect the full response (including the errors array Cloudflare returns) before validating; surface result:null + errors as an API error, not a shape failure.
- Verify the field name against the Radar API docs for the endpoint and API version in use; update the seed script if renamed.
- Check token scopes/plan entitlement for the Radar summary endpoints being queried.
- Use the correct endpoint: map-shaped summary endpoints for requireRadarObject, list-shaped ones for requireRadarArray.
Example fix
// before
const summary = requireRadarObject(result, 'clientCountries', 'traffic summary');
// after
if (result === null || Array.isArray(apiJson.errors) && apiJson.errors.length) {
throw new Error(`Radar API error: ${JSON.stringify(apiJson.errors)}`);
}
const summary = requireRadarObject(result, 'clientCountries', 'traffic summary'); Defensive patterns
Strategy: type-guard
Validate before calling
function expectRadarMap(apiJson, field) {
const result = apiJson?.result;
const v = result?.[field];
if (!v || typeof v !== 'object' || Array.isArray(v)) {
throw new Error(`Radar response missing object result.${field}: ${JSON.stringify(apiJson).slice(0, 300)}`);
}
return v;
} Type guard
const hasRadarObject = (result, field) => {
const v = result?.[field];
return !!v && typeof v === 'object' && !Array.isArray(v);
}; Try / catch
try {
const summary = requireRadarObject(result, 'clientCountries', 'traffic summary');
} catch (e) {
if (e.message.includes('missing or not an object')) {
console.error('Expected a Radar summary map; got:', typeof result?.[field], JSON.stringify(result).slice(0, 500));
throw e;
}
throw e;
} Prevention
- Match endpoint shape to validator: map endpoints for requireRadarObject, list endpoints for requireRadarArray.
- Validate the Cloudflare errors array first; result:null with errors is an API failure, not a shape bug.
- Keep a small fixture of a real Radar summary response in tests to detect schema drift early.
- Re-verify field names against Radar docs whenever bumping the API version.
When it happens
Trigger: Calling requireRadarObject on a summary result where the field is absent, null, an array, or a primitive — typically because the Radar endpoint changed its response shape or the request returned an error payload whose result is not the expected map.
Common situations: Radar summary API version changes moving/rename of map fields; error responses like {result: null, errors: [...]} from auth or quota failures being passed to the validator; accidentally pointing at an array-valued endpoint (e.g. a top-N list) instead of a map endpoint.
Related errors
- Cloudflare Radar ${source}: result.${field} is missing or no
- Redis transaction failed: ${results?.error || 'invalid respo
- DNS ${recordType} lookup failed: HTTP ${response.status}
- Invalid scorecard bloc selection.
- ECCC_PAGE_LIMIT
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/cfb0566c9e80f8e2.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/seed-internet-outages.mjs:127
return null;
})();
if (reason) throw new Error(`Cloudflare Radar ${source}: invalid success envelope (${reason})`);
return data.result;
}
/** Require an array-valued result field — an absent one is a failure, not zero records. */
function requireRadarArray(result, field, source) {
if (!Array.isArray(result[field])) {
throw new Error(`Cloudflare Radar ${source}: result.${field} is missing or not an array`);
}
return result[field];
}
/** Require an object-valued result field (Radar summary maps). */
function requireRadarObject(result, field, source) {
const value = result[field];
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(`Cloudflare Radar ${source}: result.${field} is missing or not an object`);
}
return value;
}
async function fetchOutages() {
const token = process.env.CLOUDFLARE_API_TOKEN;
if (!token) {
console.log('CLOUDFLARE_API_TOKEN not set — skipping');
process.exit(0);
}
const resp = await fetch(`${CF_RADAR_URL}?dateRange=28d&limit=50`, {
headers: {
Authorization: `Bearer ${token}`,
'User-Agent': CHROME_UA,
},
signal: AbortSignal.timeout(15_000),
});View on GitHub (pinned to 7d06c8633d)