{"record":{"id":"ebd622def3906a63","repo":"jackwener/OpenCLI","slug":"toutiao-recommend-returned-a-non-array-data-field","errorCode":null,"errorMessage":"toutiao recommend returned a non-array data field","messagePattern":"toutiao recommend returned a non-array data field","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/toutiao/recommend.js","lineNumber":64,"sourceCode":"                },\n            });\n        } catch (error) {\n            throw new CommandExecutionError(`toutiao recommend request failed: ${error?.message || error}`);\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`toutiao recommend failed: HTTP ${resp.status}`);\n        }\n        let payload;\n        try {\n            payload = await resp.json();\n        } catch (error) {\n            throw new CommandExecutionError(`toutiao recommend returned malformed JSON: ${error?.message || error}`);\n        }\n        if (payload?.message && payload.message !== 'success') {\n            throw new CommandExecutionError(`toutiao recommend returned message=${payload.message}`);\n        }\n        if (!Array.isArray(payload?.data)) {\n            throw new CommandExecutionError('toutiao recommend returned a non-array data field');\n        }\n        const rows = payload.data.map(mapRecommendRow).filter(Boolean).slice(0, limit);\n        if (rows.length === 0) {\n            throw new EmptyResultError('toutiao recommend', `频道 ${category} 返回空列表。`);\n        }\n        // Re-rank (1..N) after filter so ranks are dense even if upstream had ads.\n        return rows.map((row, idx) => ({ ...row, rank: idx + 1 }));\n    },\n});\n","sourceCodeStart":46,"sourceCodeEnd":74,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/toutiao/recommend.js#L46-L74","documentation":"This CommandExecutionError is thrown when the toutiao recommend response payload's data field is present but not an array. The library expects payload.data to be an array of recommendation rows and fails fast otherwise to prevent downstream .map() crashes.","triggerScenarios":"Calling 'toutiao recommend' when the upstream returns 200 JSON whose payload.data is null, an object, a string, or missing entirely — e.g. an error-shaped body that skipped the message check, or a schema change.","commonSituations":"Upstream contract change (data became an object keyed by category); upstream returning an error body with a different shape that still parses as JSON; partial/malformed responses during upstream incidents.","solutions":["Log the full payload once to see the actual shape of payload.data.","If upstream changed the shape, update recommend.js to read the new field (e.g. payload.data.list).","Upgrade the library if a newer version already handles the changed upstream schema.","Treat as upstream incident and retry later if the shape is normally an array."],"exampleFix":"// before\nconst rows = await recommend({ category: 'tech' });\n// after\ntry {\n  var rows = await recommend({ category: 'tech' });\n} catch (e) {\n  if (String(e.message).includes('non-array data field')) {\n    console.error('Upstream schema changed or error body returned');\n    return [];\n  }\n  throw e;\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isRecommendPayload(p) {\n  return p != null && typeof p === 'object' &&\n    (p.message === undefined || p.message === 'success') &&\n    Array.isArray(p.data);\n}","tryCatchPattern":"try {\n  return await recommend({ category });\n} catch (e) {\n  if (String(e.message).includes('non-array data field')) {\n    console.error('Upstream schema changed; inspect raw payload');\n    return [];\n  }\n  throw e;\n}","preventionTips":["Log the full payload when this fires to capture the schema change.","Keep a smoke test asserting payload.data is an array so drift is caught early.","Update the CLI/library when upstream changes the response shape.","Distinguish one-off upstream incidents from permanent contract changes."],"tags":["schema","api-contract","upstream-api","type-error"],"backgroundTag":"unexpected-response-schema","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}