{"record":{"id":"491bc908a1ca9edd","repo":"jackwener/OpenCLI","slug":"label-returned-a-non-array-data-field","errorCode":null,"errorMessage":"${label} returned a non-array data field","messagePattern":"(.+?) returned a non-array data field","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/juejin/utils.js","lineNumber":133,"sourceCode":"        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\nfunction readOptionalNumber(value, label) {\n    if (value == null) return null;\n    const n = Number(value);","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/juejin/utils.js#L115-L151","documentation":"readDataArray in clis/juejin/utils.js:133 additionally requires `payload.data` to be an array. Some Juejin endpoints return `data` as an object (e.g. `{ list: [...], cursor: ... }`) or a scalar; when that happens this CommandExecutionError is thrown instead of letting a downstream `.map()` crash with an opaque TypeError.","triggerScenarios":"Calling readDataArray on a payload whose `data` field is an object, string, or null — typically when an endpoint that returns a plain array is swapped for one that wraps results (like `{ data: { list: [...] } }`), or the API changes the data container type.","commonSituations":"Pointing the adapter at a different Juejin endpoint whose envelope nests the array one level deeper; Juejin migrating a list endpoint to a paginated object response; copy-pasting readDataArray usage onto a detail endpoint that returns a single object.","solutions":["Inspect the actual payload: if `data` is `{ list: [...] }`, unwrap it (`payload.data.list`) before or instead of calling readDataArray.","Use the correct helper for the endpoint shape — a detail/object endpoint should not go through readDataArray.","Update the adapter mapping code if Juejin changed the endpoint to a paginated object envelope.","Add a one-off normalization (e.g. `const rows = Array.isArray(p.data) ? p.data : p.data.list`) while migrating."],"exampleFix":"// before\nconst rows = readDataArray(payload, 'juejin hot'); // data is { list: [...] }\n// after\nconst raw = Array.isArray(payload.data) ? payload.data : payload.data?.list;\nconst rows = readDataArray({ ...payload, data: raw }, 'juejin hot');","handlingStrategy":"type-guard","validationCode":"const payload = JSON.parse(body);\nif (!Array.isArray(payload?.data)) {\n  // unwrap paginated object envelope before consuming\n  payload.data = payload.data?.list ?? payload.data;\n}","typeGuard":"function isDataArray(p) {\n  return p !== null && typeof p === 'object' && Array.isArray(p.data);\n}","tryCatchPattern":"try {\n  const rows = readDataArray(payload, 'juejin list');\n} catch (err) {\n  if (err instanceof CommandExecutionError && err.message.includes('non-array data field')) {\n    const unwrapped = payload.data?.list ?? [];\n    processItems(unwrapped); // handle paginated object envelope\n    return;\n  }\n  throw err;\n}","preventionTips":["Confirm the endpoint's documented shape before using readDataArray on its payload.","Normalize paginated envelopes ({data:{list:[...]}}) to plain arrays in one place.","Add a unit test per endpoint asserting Array.isArray(payload.data).","When Juejin migrates an endpoint, update the unwrapping helper rather than each call site."],"tags":["api","type-error","schema-validation","juejin"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}