jackwener/OpenCLI · error · CommandExecutionError
${label} returned a non-array data field
Error message
${label} returned a non-array data field What it means
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.
Source
Thrown at clis/juejin/utils.js:133
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;
}
function readOptionalNumber(value, label) {
if (value == null) return null;
const n = Number(value);View on GitHub (pinned to 49907e53dc)
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.
Example fix
// before
const rows = readDataArray(payload, 'juejin hot'); // data is { list: [...] }
// after
const raw = Array.isArray(payload.data) ? payload.data : payload.data?.list;
const rows = readDataArray({ ...payload, data: raw }, 'juejin hot'); Defensive patterns
Strategy: type-guard
Validate before calling
const payload = JSON.parse(body);
if (!Array.isArray(payload?.data)) {
// unwrap paginated object envelope before consuming
payload.data = payload.data?.list ?? payload.data;
} Type guard
function isDataArray(p) {
return p !== null && typeof p === 'object' && Array.isArray(p.data);
} Try / catch
try {
const rows = readDataArray(payload, 'juejin list');
} catch (err) {
if (err instanceof CommandExecutionError && err.message.includes('non-array data field')) {
const unwrapped = payload.data?.list ?? [];
processItems(unwrapped); // handle paginated object envelope
return;
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ${label} returned a malformed payload
- Chess.com stats payload for ${kind} is not an object
- Chess.com stats payload for ${kind}.last is not an object
- Chess.com stats payload for ${kind}.best is not an object
- Chess.com stats payload for ${kind}.record is not an object
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/491bc908a1ca9edd.
Report an issue: GitHub.