{"record":{"id":"935c733285d64ccd","repo":"jackwener/OpenCLI","slug":"label-returned-a-malformed-payload-935c73","errorCode":null,"errorMessage":"${label} returned a malformed payload","messagePattern":"(.+?) returned a malformed payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/juejin/utils.js","lineNumber":130,"sourceCode":"    }\n    let payload;\n    try {\n        payload = await resp.json();\n    } catch (err) {\n        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);\n    }\n    if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'err_no')) {\n        throw new CommandExecutionError(`${label} returned a malformed API envelope`);\n    }\n    if (payload.err_no !== 0) {\n        throw new CommandExecutionError(`${label} returned err_no ${payload.err_no}: ${payload.err_msg ?? ''}`);\n    }\n    return payload;\n}\n\nexport function readDataArray(payload, label) {\n    if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'data')) {\n        throw new CommandExecutionError(`${label} returned a malformed payload`);\n    }\n    if (!Array.isArray(payload.data)) {\n        throw new CommandExecutionError(`${label} returned a non-array data field`);\n    }\n    if (payload.data.length === 0) {\n        throw new EmptyResultError(label, `${label} returned no articles.`);\n    }\n    return payload.data;\n}\n\nfunction readArticleId(value, label) {\n    const id = String(value ?? '').trim();\n    if (!JUEJIN_ID.test(id)) {\n        throw new CommandExecutionError(`${label} returned a malformed article id`);\n    }\n    return id;\n}\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/juejin/utils.js#L112-L148","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Log the raw response body for the failing request to see what shape the API actually returned.","Confirm the endpoint path and request body match the current Juejin API contract; update the adapter if the key was renamed.","Check for an intercepting proxy or captive portal returning an unexpected JSON body with HTTP 200.","Retry later — if it is a partial API rollout, the shape may revert; pin/report the contract change."],"exampleFix":"// before: trusting the envelope blindly\nconst rows = readDataArray(await juejinFetch('/content_api/v1/article/query_list', body, 'juejin list'));\n// after: defensive pre-check with diagnostics\nconst payload = await juejinFetch('/content_api/v1/article/query_list', body, 'juejin list');\nif (!('data' in payload)) console.error('unexpected payload keys:', Object.keys(payload));\nconst rows = readDataArray(payload, 'juejin list');","handlingStrategy":"type-guard","validationCode":"const payload = await resp.json();\nif (payload == null || typeof payload !== 'object' || Array.isArray(payload) || !('data' in payload)) {\n  console.error('unexpected envelope:', JSON.stringify(payload).slice(0, 500));\n}","typeGuard":"function hasDataField(p) {\n  return p !== null && typeof p === 'object' && !Array.isArray(p)\n    && Object.hasOwn(p, 'data');\n}","tryCatchPattern":"try {\n  const rows = readDataArray(payload, 'juejin list');\n} catch (err) {\n  if (err instanceof CommandExecutionError && err.message.includes('malformed payload')) {\n    console.error('Envelope missing data field; dumping keys:', Object.keys(payload ?? {}));\n    return;\n  }\n  throw err;\n}","preventionTips":["Log the raw HTTP body whenever the envelope looks wrong, so contract changes are visible.","Check for proxies/captive portals that return HTTP 200 with a foreign JSON body.","Pin and review Juejin API changes before deploying adapter updates.","Route only list endpoints through readDataArray, never detail endpoints."],"tags":["api","schema-validation","response-shape","juejin"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}