koala73/worldmonitor · error

JODI Gas ZIP fetch failed: HTTP

Error message

JODI Gas ZIP fetch failed: HTTP ${resp.status}

What it means

Thrown by fetchAndParseCsv in the JODI Gas seeder when the HTTP response for the JODI Gas ZIP archive has a non-ok status. The script downloads the monthly JODI Gas world ZIP and unblocks it locally, so any 4xx/5xx from the host aborts the seed. redirect:'error' also means redirect responses surface as failures here.

Solutions

  1. Open the JODI Gas website and confirm the current ZIP URL; update zipUrl in scripts/seed-jodi-gas.mjs if the path changed.
  2. Retry later if the status is 5xx or 429 — the host is temporarily unavailable or rate limiting.
  3. Check network/proxy configuration and whether the environment allows outbound HTTPS to the JODI host.
  4. Verify the request headers (User-Agent) are not being rejected; test the URL in a browser or with curl -I.

Example fix

// before
if (!resp.ok) throw new Error(`JODI Gas ZIP fetch failed: HTTP ${resp.status}`);
// after
if (!resp.ok) {
  if (resp.status === 404) console.warn('JODI ZIP URL may be stale; check current archive path');
  throw new Error(`JODI Gas ZIP fetch failed: HTTP ${resp.status}`);
}
Defensive patterns

Strategy: retry

Validate before calling

const head = await fetch(zipUrl, { method: 'HEAD' }); if (!head.ok) console.warn(`JODI ZIP URL unhealthy: HTTP ${head.status}`);

Try / catch

try { const zip = await fetchAndParseCsv(zipUrl, signal); } catch (e) { if (/HTTP \d{3}/.test(e.message)) { console.error('JODI host returned an error status; check URL freshness or retry later', e.message); } throw e; }

Prevention

When it happens

Trigger: fetch(zipUrl) returns resp.ok === false, i.e. any HTTP 4xx/5xx status on the JODI Gas ZIP URL (e.g. 404 after the archive path changed, 403 from bot blocking, 5xx from the host).

Common situations: JODI renames or moves the monthly ZIP so the hardcoded URL 404s; CDN/WAF blocks the request despite the Chrome User-Agent; the JODI site is down for maintenance returning 5xx; an offline/proxied CI environment intercepts the request.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at scripts/seed-jodi-gas.mjs:292

}

async function fetchAndParseCsv() {
  // Discovery and archive download share the existing total request budget.
  const signal = AbortSignal.timeout(120_000);
  const catalogResponse = await fetch(CATALOG_URL, {
    headers: { 'User-Agent': CHROME_UA },
    signal,
    redirect: 'error',
  });
  if (!catalogResponse.ok) throw new Error(`JODI Gas catalog fetch failed: HTTP ${catalogResponse.status}`);
  const zipUrl = resolveGasArchiveUrl(await catalogResponse.json());
  console.log(`  Fetching JODI Gas ZIP from ${zipUrl}`);
  const resp = await fetch(zipUrl, {
    headers: { 'User-Agent': CHROME_UA, 'Accept-Encoding': 'identity' },
    signal,
    redirect: 'error',
  });
  if (!resp.ok) throw new Error(`JODI Gas ZIP fetch failed: HTTP ${resp.status}`);

  const arrayBuf = await resp.arrayBuffer();
  const zipBuf = Buffer.from(arrayBuf);
  console.log(`  ZIP downloaded: ${(zipBuf.length / 1024 / 1024).toFixed(1)} MB`);

  const entry = findZipEntry(zipBuf, CSV_FILENAME);
  if (!entry) throw new Error(`Could not find ${CSV_FILENAME} in ZIP`);
  console.log(`  Found entry: ${entry.entryName} (compression=${entry.compression})`);

  const compressed = zipBuf.slice(entry.dataOffset, entry.dataOffset + entry.compSize);
  let csvBuf;
  if (entry.compression === 0) {
    csvBuf = compressed;
  } else if (entry.compression === 8) {
    csvBuf = await inflateRawAsync(compressed);
  } else {
    throw new Error(`Unsupported ZIP compression method: ${entry.compression}`);
  }

View on GitHub (pinned to e586b8b4b8)