{"record":{"id":"d2df7b573bcf9dd3","repo":"koala73/worldmonitor","slug":"eonet-malformed-event","errorCode":null,"errorMessage":"EONET malformed event","messagePattern":"EONET malformed event","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/seed-natural-events.mjs","lineNumber":286,"sourceCode":"    const source = event.sources?.[0];\n    events.push({\n      id: event.id || '',\n      title: event.title || '',\n      description: event.description || '',\n      category: normalizedCategory,\n      categoryTitle: category.title || '',\n      lat,\n      lon,\n      date: eventDate.getTime(),\n      magnitude: latestGeo.magnitudeValue ?? 0,\n      magnitudeUnit: latestGeo.magnitudeUnit || '',\n      sourceUrl: source?.url || '',\n      sourceName: source?.id || '',\n      closed: event.closed !== null,\n    });\n  }\n\n  if (!validEonetRecords(events)) throw new Error('EONET malformed event');\n  return events;\n}\n\nfunction classifyWind(kt) {\n  if (kt >= 137) return { category: 5, classification: 'Category 5' };\n  if (kt >= 113) return { category: 4, classification: 'Category 4' };\n  if (kt >= 96) return { category: 3, classification: 'Category 3' };\n  if (kt >= 83) return { category: 2, classification: 'Category 2' };\n  if (kt >= 64) return { category: 1, classification: 'Category 1' };\n  if (kt >= 34) return { category: 0, classification: 'Tropical Storm' };\n  return { category: 0, classification: 'Tropical Depression' };\n}\n\nfunction parseNhcAdvisoryDate(value) {\n  if (typeof value !== 'string') return new Date(value).getTime();\n\n  const match = value.match(/^(\\d{1,2})(\\d{2}) (AM|PM) ([A-Z]{3,4}) (Sun|Mon|Tue|Wed|Thu|Fri|Sat) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\\d{1,2}) (\\d{4})$/);\n  if (!match) return new Date(value).getTime();","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/scripts/seed-natural-events.mjs#L268-L304","documentation":"Thrown by fetchEonet after the event loop: validEonetRecords(events) returned false, meaning the assembled EONET record list failed the seeder's aggregate validity check (e.g. too few valid records). This guards against shipping an empty or implausibly small snapshot after per-event validation passed or skipped data.","triggerScenarios":"The full EONET fetch produced an events array that fails validEonetRecords — typically zero or far fewer valid records than the threshold after filtering out earthquakes and Point-only records.","commonSituations":"EONET API outage or returning an empty events list; all events filtered out as earthquakes; a network proxy returning an empty-but-valid JSON body; wrong API URL/env producing no events.","solutions":["Log events.length and the post-filter count to see whether the API returned nothing or everything was filtered.","Retry later — EONET occasionally returns empty result sets during maintenance.","Verify the EONET request URL/params (days window, status=open) are correct and not restricting results to zero.","If a legitimately quiet period, consider lowering the validEonetRecords threshold or making it configurable."],"exampleFix":"// before\nif (!validEonetRecords(events)) throw new Error('EONET malformed event');\n// after\nif (!validEonetRecords(events)) {\n  console.warn(`EONET produced only ${events.length} valid records`);\n  throw new Error(`EONET malformed event (got ${events.length} records)`);\n}","handlingStrategy":"fallback","validationCode":"const preview = await fetchEventSourceJson('eonet', url, fetchFn); if (!Array.isArray(preview?.events) || preview.events.length === 0) console.warn('EONET returned no events; seed will fail validity check');","typeGuard":"function hasEnoughRecords(events) { return Array.isArray(events) && events.length > 0; }","tryCatchPattern":"try { const events = await fetchEonet(fetchFn); } catch (e) { if (e.message === 'EONET malformed event') { console.error('EONET aggregate validity failed; falling back to previous snapshot'); return previousSnapshot; } throw e; }","preventionTips":["Keep the previous successful snapshot and serve it when the fresh fetch fails validity","Log the event count before and after filtering to distinguish outage from over-filtering","Make the minimum-record threshold configurable for legitimately quiet periods","Monitor EONET status endpoints before scheduled seeds"],"tags":["api","validation","nasa-eonet","empty-result"],"backgroundTag":"empty-result-set","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"}