koala73/worldmonitor · error

GDACS SEARCH page incomplete (VO)

Error message

GDACS SEARCH page incomplete (VO)

What it means

Thrown by fetchGdacsType when fetching volcanoes (eventtype 'VO'): GDACS SEARCH pagination returns a full page (>= 100 features, the pageSize), so there may be more pages and the snapshot would be incomplete. The seeder refuses to cap silently at one page.

Solutions

  1. Implement follow-up pagination: request pageNumber 2+ until a page returns fewer than pageSize features.
  2. Retry later if the count is borderline (e.g. exactly 100) — the active-event count may drop below the page size.
  3. Verify the SEARCH query filters (alert levels, active-only) are not accidentally widening the result set.
  4. If intentional, raise pageSize above 100 if the GDACS endpoint supports it.

Example fix

// before
if (eventtype === 'VO' && data.features.length >= 100) throw new Error('GDACS SEARCH page incomplete (VO)');
// after
let features = data.features;
let page = 1;
while (eventtype === 'VO' && features.length >= 100 * page) {
  const next = await fetchEventSourceJson(`gdacs:${eventtype}`, urlWithPage(++page), fetchFn);
  features = features.concat(next.features);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const count = (data?.features || []).length; if (count >= 100) console.warn('GDACS VO page full; pagination required for a complete snapshot');

Try / catch

try { const points = await fetchGdacsType('VO', fetchFn); } catch (e) { if (e.message.includes('GDACS SEARCH page incomplete')) { console.error('More than one page of volcano events; implement page following or retry'); } throw e; }

Prevention

When it happens

Trigger: eventtype === 'VO' and data.features.length >= 100 — exactly pageSize, meaning at least one more page of volcano events likely exists.

Common situations: An unusually active volcanic period exceeding 100 concurrent GDACS volcano events; a GDACS query change returning duplicate/all-history entries inflating the count past one page.

Related errors


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

Appendix: source

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

async function fetchGdacsType(eventtype, fetchFn, now) {
  // MAP requires one type, but its VO route returns 404. SEARCH supplies
  // recent volcano events; their iscurrent field determines closure below.
  const url = new URL(eventtype === 'VO' ? GDACS_API.replace(/MAP$/, 'SEARCH') : GDACS_API);
  if (eventtype === 'VO') {
    url.search = new URLSearchParams({
      eventlist: 'VO',
      fromDate: new Date(now - DAYS * 86_400_000).toISOString().slice(0, 10),
      toDate: new Date(now).toISOString().slice(0, 10),
      pageSize: '100', pageNumber: '1',
    }).toString();
  } else url.searchParams.set('eventtype', eventtype);
  const data = await fetchEventSourceJson(`gdacs:${eventtype}`, url.toString(), fetchFn);
  if (!Array.isArray(data?.features) || data.features.some(feature =>
    !['Point', 'Polygon', 'MultiPolygon', 'LineString', 'MultiLineString'].includes(feature?.geometry?.type))) {
    throw new Error(`GDACS malformed response (${eventtype})`);
  }
  if (eventtype === 'VO' && data.features.length >= 100) throw new Error('GDACS SEARCH page incomplete (VO)');
  // MAP also carries impact polygons and forecast tracks. They are not event
  // records; retaining them would inflate snapshots without adding coverage.
  const points = data.features.filter(feature => feature.geometry.type === 'Point');
  if (!validGdacsFeatures(points, eventtype)) throw new Error(`GDACS malformed response (${eventtype})`);
  return points;
}

const GDACS_ALERT_RANK = { Red: 0, Orange: 1 };

export async function fetchGdacs(fetchFn = globalThis.fetch, { previousSources = null, now = Date.now() } = {}) {
  const types = Object.keys(GDACS_TO_CATEGORY);
  const settled = await Promise.allSettled(types.map((eventtype) => fetchGdacsType(eventtype, fetchFn, now)));
  const failedTypes = [];
  const features = [];
  const snapshots = {};
  settled.forEach((result, i) => {
    const type = types[i];
    const source = `gdacs:${type}`;

View on GitHub (pinned to e586b8b4b8)