jackwener/OpenCLI · error · CommandExecutionError

${label} returned a malformed payload

Error message

${label} returned a malformed payload

What it means

readDataArray in clis/juejin/utils.js:130 requires the API payload to be a non-null, non-array object that has its own `data` property. If the envelope lacks `data` entirely (or the payload is not an object), it throws this CommandExecutionError. It guards callers against Juejin changing or degrading its response shape.

Source

Thrown at clis/juejin/utils.js:130

    }
    let payload;
    try {
        payload = await resp.json();
    } catch (err) {
        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
    }
    if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'err_no')) {
        throw new CommandExecutionError(`${label} returned a malformed API envelope`);
    }
    if (payload.err_no !== 0) {
        throw new CommandExecutionError(`${label} returned err_no ${payload.err_no}: ${payload.err_msg ?? ''}`);
    }
    return payload;
}

export function readDataArray(payload, label) {
    if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'data')) {
        throw new CommandExecutionError(`${label} returned a malformed payload`);
    }
    if (!Array.isArray(payload.data)) {
        throw new CommandExecutionError(`${label} returned a non-array data field`);
    }
    if (payload.data.length === 0) {
        throw new EmptyResultError(label, `${label} returned no articles.`);
    }
    return payload.data;
}

function readArticleId(value, label) {
    const id = String(value ?? '').trim();
    if (!JUEJIN_ID.test(id)) {
        throw new CommandExecutionError(`${label} returned a malformed article id`);
    }
    return id;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the raw response body for the failing request to see what shape the API actually returned.
  2. Confirm the endpoint path and request body match the current Juejin API contract; update the adapter if the key was renamed.
  3. Check for an intercepting proxy or captive portal returning an unexpected JSON body with HTTP 200.
  4. Retry later — if it is a partial API rollout, the shape may revert; pin/report the contract change.

Example fix

// before: trusting the envelope blindly
const rows = readDataArray(await juejinFetch('/content_api/v1/article/query_list', body, 'juejin list'));
// after: defensive pre-check with diagnostics
const payload = await juejinFetch('/content_api/v1/article/query_list', body, 'juejin list');
if (!('data' in payload)) console.error('unexpected payload keys:', Object.keys(payload));
const rows = readDataArray(payload, 'juejin list');
Defensive patterns

Strategy: type-guard

Validate before calling

const payload = await resp.json();
if (payload == null || typeof payload !== 'object' || Array.isArray(payload) || !('data' in payload)) {
  console.error('unexpected envelope:', JSON.stringify(payload).slice(0, 500));
}

Type guard

function hasDataField(p) {
  return p !== null && typeof p === 'object' && !Array.isArray(p)
    && Object.hasOwn(p, 'data');
}

Try / catch

try {
  const rows = readDataArray(payload, 'juejin list');
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.includes('malformed payload')) {
    console.error('Envelope missing data field; dumping keys:', Object.keys(payload ?? {}));
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: A juejinFetch result whose body parses as JSON but has no `data` key — e.g. the API returned `{ err_no: 0, err_msg: 'success' }` without data, an error object shape, or the endpoint silently changed its response contract.

Common situations: Juejin deploying an API revision that renames or omits `data`; a proxy/captive portal returning a 200 JSON page that is not the expected envelope; hitting an endpoint variant that nests results under a different key.

Understand the failure class

Related errors


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