{"record":{"id":"bfee243a27dc7330","repo":"jackwener/OpenCLI","slug":"nowcoder-source-returned-malformed-records","errorCode":null,"errorMessage":"Nowcoder ${source} returned malformed records","messagePattern":"Nowcoder (.+?) returned malformed records","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/nowcoder/posts.js","lineNumber":167,"sourceCode":"        const post = data.momentData;\n        const entityId = requiredId(post.id, 'moment entity id');\n        if ((requireOuterId || data.contentId != null) && entityId !== requiredId(data.contentId, 'moment feed id')) {\n            throw new CommandExecutionError('Nowcoder returned mismatched moment feed identity');\n        }\n        const uuid = requiredUuid(post.uuid, 'moment uuid');\n        return {\n            ...commonFeedFields(data, post, 'moment', post.userId, post.createdAt, index),\n            id: uuid,\n            uuid,\n            entity_id: entityId,\n            url: `https://www.nowcoder.com/feed/main/detail/${uuid}`,\n        };\n    }\n    throw new CommandExecutionError(`Nowcoder returned unsupported feed contentType ${String(data.contentType)}`);\n}\n\nexport function projectNowcoderFeed(records, limit, source, wrapped = false) {\n    if (!Array.isArray(records)) throw new CommandExecutionError(`Nowcoder ${source} returned malformed records`);\n    const rows = [];\n    for (const record of records) {\n        const data = wrapped ? record?.data : record;\n        rows.push(projectFeedData(data, rows.length, source === 'experience' || wrapped));\n    }\n    if (rows.length === 0) throw new EmptyResultError(`nowcoder ${source}`, 'Nowcoder returned no content or moment posts.');\n    return rows.slice(0, limit);\n}\n\nexport function parseNowcoderPostTarget(raw) {\n    const value = typeof raw === 'string' ? raw.trim() : '';\n    if (NUMERIC_ID_PATTERN.test(value)) return { post_type: 'content', value };\n    if (UUID_PATTERN.test(value)) return { post_type: 'moment', value: value.toLowerCase() };\n\n    let url;\n    try {\n        url = new URL(value);\n    }","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/nowcoder/posts.js#L149-L185","documentation":"projectNowcoderFeed is the public entry point for normalizing Nowcoder feed responses into post rows. It requires the records argument to be a real array; anything else (null, an object, a string) is rejected with this error, which names the source ('recommend', 'experience', etc.) so you know which feed failed. It guards against passing raw response envelopes or undefined fetch results straight into projection.","triggerScenarios":"Calling projectNowcoderFeed(records, limit, source) where records is not an Array — typically the payload.data field of a response was passed instead of its array member (e.g., data.feed.records), or a fetch returned null/undefined.","commonSituations":"Extracting the wrong key from the Nowcoder JSON envelope after an API change; passing the whole {success, code, data} object instead of data's inner list; a fetch helper returning undefined on error being piped directly into projection.","solutions":["Locate the correct array in the response (e.g., payload.data.records or payload.data.feed.list) and pass that to projectNowcoderFeed.","Use fetchNowcoderData to validate the envelope first, then pick the array field it returns.","Add a console.log/Object.keys inspection of the response object to find where the list now lives.","If you must tolerate missing data, check Array.isArray before calling and surface your own error."],"exampleFix":"// before\nconst rows = projectNowcoderFeed(payload, 10, 'recommend');\n// after\nconst rows = projectNowcoderFeed(payload.data.feed.records, 10, 'recommend');","handlingStrategy":"validation","validationCode":"if (!Array.isArray(records)) throw new TypeError(`expected feed records array, got ${typeof records}`);\nconst rows = projectNowcoderFeed(records, limit, source, wrapped);","typeGuard":"function isFeedRecords(value) { return Array.isArray(value); }","tryCatchPattern":"try {\n    rows = projectNowcoderFeed(records, limit, source, wrapped);\n} catch (error) {\n    if (String(error.message).includes('returned malformed records')) {\n        throw new Error(`Feed source '${source}' did not yield an array; inspect the response shape`);\n    }\n    throw error;\n}","preventionTips":["Pass the array member of the response (e.g., payload.data.records), not the envelope","Validate the envelope with fetchNowcoderData before projecting","Assert Array.isArray on integration boundaries in tests","Check for null/undefined fetch results before piping into projection"],"tags":["feed-parsing","argument-validation","api-response"],"backgroundTag":"invalid-argument-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}