{"record":{"id":"ea3d506031278fd7","repo":"koala73/worldmonitor","slug":"eonet-malformed-event-geometry","errorCode":null,"errorMessage":"EONET malformed event geometry","messagePattern":"EONET malformed event geometry","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/seed-natural-events.mjs","lineNumber":259,"sourceCode":"    }\n  }, 1, 500);\n}\n\nasync function fetchEonet(days, fetchFn = globalThis.fetch, now = Date.now()) {\n  const url = `${EONET_API_URL}?status=open&days=${days}`;\n  const data = await fetchEventSourceJson('eonet', url, fetchFn);\n  if (!Array.isArray(data?.events)) throw new Error('EONET malformed response');\n  const events = [];\n\n  for (const event of data.events || []) {\n    const category = event.categories?.[0];\n    if (!category) throw new Error('EONET malformed event category');\n    const normalizedCategory = normalizeCategory(category.id);\n    if (normalizedCategory === 'earthquakes') continue;\n\n    const latestGeo = event.geometry?.[event.geometry.length - 1];\n    if (!latestGeo || !['Point', 'Polygon'].includes(latestGeo.type) || !Array.isArray(latestGeo.coordinates)) {\n      throw new Error('EONET malformed event geometry');\n    }\n    if (latestGeo.type !== 'Point') continue;\n\n    const eventDate = new Date(latestGeo.date);\n    const [lon, lat] = latestGeo.coordinates;\n\n    if (normalizedCategory === 'wildfires' && now - eventDate.getTime() > WILDFIRE_MAX_AGE_MS) continue;\n\n    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(),","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/scripts/seed-natural-events.mjs#L241-L277","documentation":"Thrown by fetchEonet when an event's latest geometry entry is missing, is not a Point/Polygon, or lacks a coordinates array. The seeder validates each event's most recent geometry before extracting lon/lat for Point records.","triggerScenarios":"event.geometry is empty or undefined; the last geometry item has a type outside ['Point','Polygon'] (e.g. missing type), or its coordinates is not an array.","commonSituations":"EONET serving events with empty geometry arrays (very new or archived events); upstream schema changes to geometry entries; cached/partial API responses in CI.","solutions":["Inspect the raw EONET response to identify events with empty/odd geometry; confirm whether the API is returning partial data.","Retry the seed to rule out a transient truncated response.","Change the handling to skip (continue) events with unusable geometry rather than throwing for the whole batch.","If persistent, check EONET API changelog for geometry format changes and update the validator."],"exampleFix":"// before\nif (!latestGeo || !['Point', 'Polygon'].includes(latestGeo.type) || !Array.isArray(latestGeo.coordinates)) {\n  throw new Error('EONET malformed event geometry');\n}\n// after\nif (!latestGeo || !['Point', 'Polygon'].includes(latestGeo.type) || !Array.isArray(latestGeo.coordinates)) {\n  console.warn('Skipping EONET event with malformed geometry', event.id);\n  continue;\n}","handlingStrategy":"validation","validationCode":"const geoOk = (data?.events || []).every(e => { const g = e?.geometry?.[e.geometry.length - 1]; return g && ['Point','Polygon'].includes(g.type) && Array.isArray(g.coordinates); });","typeGuard":"function hasValidGeometry(event) { const g = event?.geometry?.[event.geometry.length - 1]; return !!g && ['Point', 'Polygon'].includes(g.type) && Array.isArray(g.coordinates); }","tryCatchPattern":"try { const events = await fetchEonet(fetchFn); } catch (e) { if (e.message === 'EONET malformed event geometry') { console.error('An EONET event lacked usable geometry; check for empty geometry arrays'); } throw e; }","preventionTips":["Treat empty geometry arrays as skippable events, not fatal errors","Log event ids of skipped/malformed records for upstream reporting","Cache the last good EONET snapshot and fall back to it on validation failure","Test the seeder against a recorded EONET fixture to catch schema drift early"],"tags":["api","geojson","schema-validation","nasa-eonet"],"backgroundTag":"unexpected-response-shape","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"}