koala73/worldmonitor · error
JODI Gas catalog has no valid publication
Error message
JODI Gas catalog has no valid publication
What it means
resolveGasArchiveUrl() validates the JODI Gas catalog JSON before using it: it requires a positive safe-integer publicationId and an array files. If either is missing or of the wrong type/shape, it throws 'JODI Gas catalog has no valid publication'. This detects upstream catalog format changes or partial responses before any URL is constructed.
Solutions
- Inspect the raw catalog JSON from CATALOG_URL and compare against the expected shape (publicationId as positive integer, files array)
- Update resolveGasArchiveUrl() and seed-jodi-gas.mjs if the JODI catalog schema changed
- Re-run after confirming the endpoint returns the genuine catalog (no proxy/error JSON)
- Check seed-meta/cache for a stale catalog copy being validated
Example fix
// before
throw new Error('JODI Gas catalog has no valid publication');
// after (surface what actually came back)
throw new Error(`JODI Gas catalog has no valid publication: ${JSON.stringify(catalog).slice(0, 200)}`); Defensive patterns
Strategy: type-guard
Validate before calling
if (!Number.isSafeInteger(catalog?.publicationId) || catalog.publicationId <= 0 || !Array.isArray(catalog.files)) {
throw new Error('catalog shape invalid before calling resolveGasArchiveUrl');
} Type guard
function hasValidPublication(catalog) {
return Number.isSafeInteger(catalog?.publicationId) && catalog.publicationId > 0 && Array.isArray(catalog?.files);
} Try / catch
try {
const zipUrl = resolveGasArchiveUrl(catalog);
} catch (err) {
if (err.message.includes('no valid publication')) console.error('Catalog JSON shape changed; inspect the raw payload');
throw err;
} Prevention
- Validate the catalog JSON shape right after fetching, before use
- Snapshot the raw catalog response when validation fails for diagnosis
- Watch for upstream schema changes and update the validator accordingly
When it happens
Trigger: The catalog endpoint returns JSON without publicationId (schema change), with a string or float id, or with files absent/null; a proxy or error page returns JSON that isn't the real catalog.
Common situations: JODI publishes a new catalog schema, an intermediate/proxy replaces the response, or a cached/stale catalog snapshot is validated.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- JODI Gas catalog must contain one supported CSV archive
- Compact health payload must be an object
- Compact health pending entries must be objects
- Compact health pending must be an object
- Convex embed key validation unavailable: invalid-payload
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/ed4f57cf49615ae0.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/seed-jodi-gas.mjs:267
if (!filename || entryName === filename || entryName.endsWith('/' + filename)) {
if ((flags & 0x08) && compSize === 0) {
throw new Error(`JODI Gas ZIP: entry uses data-descriptor (bit 3) — compSize unknown in local header`);
}
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());View on GitHub (pinned to e586b8b4b8)