koala73/worldmonitor · error

EONET malformed event geometry

Error message

EONET malformed event geometry

What it means

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.

Solutions

  1. Inspect the raw EONET response to identify events with empty/odd geometry; confirm whether the API is returning partial data.
  2. Retry the seed to rule out a transient truncated response.
  3. Change the handling to skip (continue) events with unusable geometry rather than throwing for the whole batch.
  4. If persistent, check EONET API changelog for geometry format changes and update the validator.

Example fix

// before
if (!latestGeo || !['Point', 'Polygon'].includes(latestGeo.type) || !Array.isArray(latestGeo.coordinates)) {
  throw new Error('EONET malformed event geometry');
}
// after
if (!latestGeo || !['Point', 'Polygon'].includes(latestGeo.type) || !Array.isArray(latestGeo.coordinates)) {
  console.warn('Skipping EONET event with malformed geometry', event.id);
  continue;
}
Defensive patterns

Strategy: validation

Validate before calling

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); });

Type guard

function hasValidGeometry(event) { const g = event?.geometry?.[event.geometry.length - 1]; return !!g && ['Point', 'Polygon'].includes(g.type) && Array.isArray(g.coordinates); }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: EONET serving events with empty geometry arrays (very new or archived events); upstream schema changes to geometry entries; cached/partial API responses in CI.

Understand the failure class

Related errors


AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22). Data as JSON: /api/errors/ea3d506031278fd7. Report an issue: GitHub.

Appendix: source

Thrown at scripts/seed-natural-events.mjs:259

    }
  }, 1, 500);
}

async function fetchEonet(days, fetchFn = globalThis.fetch, now = Date.now()) {
  const url = `${EONET_API_URL}?status=open&days=${days}`;
  const data = await fetchEventSourceJson('eonet', url, fetchFn);
  if (!Array.isArray(data?.events)) throw new Error('EONET malformed response');
  const events = [];

  for (const event of data.events || []) {
    const category = event.categories?.[0];
    if (!category) throw new Error('EONET malformed event category');
    const normalizedCategory = normalizeCategory(category.id);
    if (normalizedCategory === 'earthquakes') continue;

    const latestGeo = event.geometry?.[event.geometry.length - 1];
    if (!latestGeo || !['Point', 'Polygon'].includes(latestGeo.type) || !Array.isArray(latestGeo.coordinates)) {
      throw new Error('EONET malformed event geometry');
    }
    if (latestGeo.type !== 'Point') continue;

    const eventDate = new Date(latestGeo.date);
    const [lon, lat] = latestGeo.coordinates;

    if (normalizedCategory === 'wildfires' && now - eventDate.getTime() > WILDFIRE_MAX_AGE_MS) continue;

    const source = event.sources?.[0];
    events.push({
      id: event.id || '',
      title: event.title || '',
      description: event.description || '',
      category: normalizedCategory,
      categoryTitle: category.title || '',
      lat,
      lon,
      date: eventDate.getTime(),

View on GitHub (pinned to e586b8b4b8)