koala73/worldmonitor · error
JODI Gas catalog must contain one supported CSV archive
Error message
JODI Gas catalog must contain one supported CSV archive
What it means
resolveGasArchiveUrl() expects the catalog's files array to contain exactly one usable CSV entry (format === 'CSV' and ignore === false) whose filename is 'GAS_world_NewFormat.zip'. If the count differs or the filename changed, it throws 'JODI Gas catalog must contain one supported CSV archive'. This pins the downloader to the known-supported archive so a silent upstream rename or new file doesn't seed wrong data.
Solutions
- Log/print the catalog.files entries to see what changed
- Update the expected filename constant and validation to the new archive name after confirming it is the correct successor
- Relax or extend the filter if multiple legitimate CSV archives now exist and pick the right one deterministically
- Re-run the seed once the catalog again lists the supported archive
Example fix
// before
if (csvFiles.length !== 1 || csvFiles[0].filename !== 'GAS_world_NewFormat.zip') {
throw new Error('JODI Gas catalog must contain one supported CSV archive');
}
// after
const EXPECTED = 'GAS_world_NewFormat.zip'; // update if JODI renames the archive
if (csvFiles.length !== 1 || csvFiles[0].filename !== EXPECTED) {
throw new Error(`JODI Gas catalog must contain one supported CSV archive; got: ${csvFiles.map(f => f.filename).join(', ')}`);
} Defensive patterns
Strategy: type-guard
Validate before calling
const csvFiles = (catalog?.files ?? []).filter(f => f?.format === 'CSV' && f.ignore === false);
if (csvFiles.length !== 1 || csvFiles[0].filename !== 'GAS_world_NewFormat.zip') {
console.error('unexpected CSV archive set:', csvFiles.map(f => f?.filename));
} Type guard
function hasSupportedArchive(catalog) {
const csv = (catalog?.files ?? []).filter(f => f?.format === 'CSV' && f.ignore === false);
return csv.length === 1 && csv[0].filename === 'GAS_world_NewFormat.zip';
} Try / catch
try {
const zipUrl = resolveGasArchiveUrl(catalog);
} catch (err) {
if (err.message.includes('one supported CSV archive')) console.error('JODI catalog archive name/set changed; review catalog.files');
throw err;
} Prevention
- Log catalog.files when validation fails so upstream renames are visible
- Keep the expected filename in a single named constant for easy updates
- Periodically verify the catalog still lists the expected archive
When it happens
Trigger: JODI renames the archive (e.g. GAS_world_v2.zip), adds a second CSV entry, marks the expected file ignore:true, or publishes a different format entry — any of which changes csvFiles to not be exactly one entry named GAS_world_NewFormat.zip.
Common situations: Upstream release format change at JODI, a new data product added to the catalog alongside the classic archive, or a temporary catalog publishing zero available files.
Related errors
- JODI Gas catalog has no valid publication
- JODI Gas catalog fetch failed: HTTP
- a pull_request payload is required
- A valid country code is required for a resilience score…
- Aircraft identifier is too long
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/29bfde2a00221110.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/seed-jodi-gas.mjs:271
return { dataOffset, compSize, compression, entryName };
}
// If bit 3 is set, compSize in local header is 0 — fall back to byte scan
if ((flags & 0x08) && compSize === 0) { offset++; continue; }
offset = dataOffset + compSize;
}
return null;
}
// Publication IDs identify specific releases. Follow the same catalog as the
// official download page; a successful fetch of an old ID never finds new data.
function resolveGasArchiveUrl(catalog) {
if (!Number.isSafeInteger(catalog?.publicationId) || catalog.publicationId <= 0
|| !Array.isArray(catalog.files)) {
throw new Error('JODI Gas catalog has no valid publication');
}
const csvFiles = catalog.files.filter(file => file?.format === 'CSV' && file.ignore === false);
if (csvFiles.length !== 1 || csvFiles[0].filename !== 'GAS_world_NewFormat.zip') {
throw new Error('JODI Gas catalog must contain one supported CSV archive');
}
return `${ARCHIVE_ROOT}/${catalog.publicationId}/${csvFiles[0].filename}`;
}
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,View on GitHub (pinned to e586b8b4b8)