{"record":{"id":"ed75cf7a4b4b8490","repo":"koala73/worldmonitor","slug":"gdacs-unavailable-failedtypes-map-t-t-message-join","errorCode":null,"errorMessage":"GDACS unavailable: ${failedTypes.map((t) => t.message).join('; ')}","messagePattern":"GDACS unavailable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"scripts/seed-natural-events.mjs","lineNumber":406,"sourceCode":"\nconst GDACS_ALERT_RANK = { Red: 0, Orange: 1 };\n\nexport async function fetchGdacs(fetchFn = globalThis.fetch, { previousSources = null, now = Date.now() } = {}) {\n  const types = Object.keys(GDACS_TO_CATEGORY);\n  const settled = await Promise.allSettled(types.map((eventtype) => fetchGdacsType(eventtype, fetchFn, now)));\n  const failedTypes = [];\n  const features = [];\n  const snapshots = {};\n  settled.forEach((result, i) => {\n    const type = types[i];\n    const source = `gdacs:${type}`;\n    const snapshot = selectSourceSnapshot(result, previousSources?.[source], now, records => validGdacsFeatures(records, type));\n    snapshots[source] = snapshot;\n    if (snapshot) features.push(...snapshot.records);\n    if (result.status === 'rejected') failedTypes.push({ eventtype: type, message: result.reason?.message || String(result.reason) });\n  });\n  if (failedTypes.length === types.length && !Object.values(snapshots).some(Boolean)) {\n    throw new Error(`GDACS unavailable: ${failedTypes.map((t) => t.message).join('; ')}`);\n  }\n\n  // The 100-event cap used to fall on GDACS's own mixed-type ordering. The\n  // per-type lists arrive grouped, so capping the raw concatenation would let\n  // 100 earthquakes evict every cyclone, including the TC members the\n  // western-Pacific snapshot is built from. Rank by alert level, then newest\n  // first, so the cap drops the least urgent events regardless of type.\n  const rank = (f) => GDACS_ALERT_RANK[f?.properties?.alertlevel] ?? 2;\n  const started = (f) => new Date(f?.properties?.fromdate || 0).getTime() || 0;\n  features.sort((a, b) => rank(a) - rank(b) || started(b) - started(a));\n\n  const seen = new Set();\n  const events = [];\n\n  for (const f of features) {\n    if (!f.geometry || f.geometry.type !== 'Point') continue;\n    const props = f.properties;\n    const key = `${props.eventtype}-${props.eventid}`;","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/scripts/seed-natural-events.mjs#L388-L424","documentation":"Aggregate failure thrown by fetchGdacs: every requested GDACS event type's fetch was rejected and no fallback snapshot (from previousSources) was available for any type. The message concatenates each per-type failure message, so it reports all underlying causes at once.","triggerScenarios":"All types in the fetchGdacs type list fail (fetchGdacsType threw for each — network errors, malformed responses, pagination errors) AND every snapshots[source] entry is null/undefined.","commonSituations":"GDACS is fully down or blocking the seeder's IP/WAF; total network outage in CI; a GDACS API endpoint migration breaking all type feeds simultaneously; credentials/proxy misconfiguration cutting all outbound requests.","solutions":["Read the joined per-type messages in the error to identify the common cause (all network vs all schema failures).","Check GDACS service status and test one feed URL directly with curl.","Retry with backoff — the all-types failure is usually transient outage or rate limiting.","Verify network/proxy/egress configuration in the environment running the seed."],"exampleFix":"// before\nif (failedTypes.length === types.length && !Object.values(snapshots).some(Boolean)) {\n  throw new Error(`GDACS unavailable: ${failedTypes.map((t) => t.message).join('; ')}`);\n}\n// after\nif (failedTypes.length === types.length && !Object.values(snapshots).some(Boolean)) {\n  throw new Error(`GDACS unavailable: ${failedTypes.map((t) => t.message).join('; ')}`); // inspect per-type messages above\n}","handlingStrategy":"retry","validationCode":"const probe = await fetch('https://www.gdacs.org/gdacsapi/api/events/getevents/SEARCH'); if (!probe.ok) console.warn(`GDACS unreachable: HTTP ${probe.status}`);","typeGuard":null,"tryCatchPattern":"try { const gdacs = await fetchGdacs(fetchFn, { previousSources }); } catch (e) { if (e.message.startsWith('GDACS unavailable:')) { console.error('All GDACS types failed:', e.message); // schedule retry with backoff } throw e; }","preventionTips":["Retry the whole fetchGdacs batch with exponential backoff before giving up","Serve last-known-good snapshots (previousSources) when all types fail","Monitor GDACS availability from CI before running scheduled seeds","Check egress/proxy config — an all-types failure usually means environment, not schema"],"tags":["api","network","gdacs","total-outage"],"backgroundTag":"upstream-api-error","analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-09-22T01:50:49.965Z","contentChangedAt":"2026-09-22T01:50:49.965Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}