jackwener/OpenCLI · error · CommandExecutionError

archive snapshots returned malformed CDX payload: header…

Error message

archive snapshots returned malformed CDX payload: header row must be an array

What it means

The CDX payload is an array-of-arrays with a header row, but the header row itself is not an array, so column names cannot be mapped to indexes. The library throws this because the CDX JSON contract requires `[["col1","col2",...], [row...], ...]`; anything else means the response shape changed or was substituted.

Solutions

  1. Inspect the raw payload with curl to confirm the header row shape.
  2. Confirm the command targets the standard CDX endpoint (`http://web.archive.org/cdx/search/cdx`) and not a modified proxy URL.
  3. Check for opencli updates that accommodate CDX response changes.
  4. Report upstream if the CDX API contract changed for your query shape.
Defensive patterns

Strategy: type-guard

Validate before calling

const probe = await fetch('http://web.archive.org/cdx/search/cdx?url=example.com&output=json&limit=1');
const body = JSON.parse(await probe.text());
if (!Array.isArray(body) || !Array.isArray(body[0])) console.warn('Unexpected CDX header shape');

Type guard

function hasArrayHeader(payload) {
  return Array.isArray(payload) && payload.length > 0 && Array.isArray(payload[0]);
}

Try / catch

try {
  await exec('opencli archive snapshots example.com');
} catch (e) {
  if (String(e.message).includes('header row must be an array')) {
    console.error('CDX contract changed — inspect raw payload and update tooling');
  } else throw e;
}

Prevention

When it happens

Trigger: The parsed JSON's first element is not an array — e.g. a flat array of objects, a plain string, or a numeric value returned instead of the expected `[header, ...rows]` structure; typically from an API change or a non-CDX JSON body.

Common situations: Wayback CDX API contract changes; hitting a different/mirror endpoint that returns object-per-row JSON; a gateway returning a compact JSON error array of strings.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/870e55a9875aab9d. Report an issue: GitHub.

Appendix: source

Thrown at clis/archive/snapshots.js:97

            throw new CommandExecutionError(`archive snapshots failed: HTTP ${resp.status}`);
        }
        let data;
        try {
            data = await resp.json();
        } catch (error) {
            throw new CommandExecutionError(`archive snapshots returned malformed JSON: ${error?.message || error}`);
        }

        // CDX returns an array of arrays; the first row is the header.
        if (!Array.isArray(data)) {
            throw new CommandExecutionError('archive snapshots returned malformed CDX payload: top-level payload must be an array');
        }
        if (data.length < 2) {
            throw new EmptyResultError('archive snapshots', `No Wayback snapshots for "${target}".`);
        }
        const [header, ...rows] = data;
        if (!Array.isArray(header)) {
            throw new CommandExecutionError('archive snapshots returned malformed CDX payload: header row must be an array');
        }
        const cols = {};
        header.forEach((name, i) => { cols[name] = i; });
        const timestampCol = requireCdxColumn(cols, 'timestamp');
        const originalCol = requireCdxColumn(cols, 'original');
        const statusCol = requireCdxColumn(cols, 'statuscode');
        const mimetypeCol = requireCdxColumn(cols, 'mimetype');

        return rows.slice(0, limit).map(row => {
            if (!Array.isArray(row)) {
                throw new CommandExecutionError('archive snapshots returned malformed CDX payload: snapshot row must be an array');
            }
            const timestamp = String(row[timestampCol] ?? '');
            const original = String(row[originalCol] ?? '');
            const status = row[statusCol];
            const mimetype = row[mimetypeCol];
            if (!/^\d{14}$/.test(timestamp) || !original) {
                throw new CommandExecutionError('archive snapshots returned malformed CDX payload: snapshot row is missing timestamp/original URL');

View on GitHub (pinned to 49907e53dc)