jackwener/OpenCLI · error · CommandExecutionError

archive snapshots returned malformed CDX payload: header row

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.

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)

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.