{"record":{"id":"b3fda962bae72219","repo":"jackwener/OpenCLI","slug":"webhost-feed-malformed-feed-item","errorCode":null,"errorMessage":"${webHost} feed: malformed feed item","messagePattern":"(.+?) feed: malformed feed item","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/feed.js","lineNumber":118,"sourceCode":"    // Pinia store hydrates from SSR; give the page a beat to finish\n    // bootstrapping before reading the array.\n    await page.wait({ time: 2 });\n    const data = unwrapEvaluateResult(await page.evaluate(FEEDS_READ_JS));\n    if (!data || typeof data !== 'object') {\n        throw new CommandExecutionError(`${webHost} feed: unexpected evaluate response`);\n    }\n    if (data.error) {\n        throw new CommandExecutionError(`${webHost} feed: ${data.error}`, `The SPA may still be hydrating; reload ${webHost}/explore and retry.`);\n    }\n    if (!Array.isArray(data.items)) {\n        throw new CommandExecutionError(`${webHost} feed: unexpected items payload shape`);\n    }\n    const rows = [];\n    for (const row of data.items) {\n        if (rows.length >= limit)\n            break;\n        if (!row || typeof row !== 'object') {\n            throw new CommandExecutionError(`${webHost} feed: malformed feed item`);\n        }\n        const id = toCleanString(row.id);\n        if (!id) {\n            throw new CommandExecutionError(`${webHost} feed: feed item is missing note id`);\n        }\n        const xsecToken = toCleanString(row.xsecToken);\n        if (!xsecToken) {\n            throw new CommandExecutionError(`${webHost} feed: feed item ${id} is missing xsecToken; cannot build a signed drill-down URL`);\n        }\n        rows.push({\n            id,\n            title: toCleanString(row.title),\n            type: toCleanString(row.type),\n            author: toCleanString(row.author),\n            likes: toCleanString(row.likes),\n            url: buildFeedNoteUrl(webHost, id, xsecToken),\n        });\n    }","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/feed.js#L100-L136","documentation":"Each entry in data.items must be a non-null object. runFeed throws 'malformed feed item' when a row is null, undefined, or a primitive. This is a per-item integrity check while building the result rows.","triggerScenarios":"data.items contains null/undefined entries or primitive values (strings/numbers) instead of note objects.","commonSituations":"Site inserts placeholder/ad entries as null, partial SSR hydration leaving holes in the items array, site schema change where items are keyed objects rather than an array of objects.","solutions":["Filter out non-object rows before parsing instead of failing the whole command","Update FEEDS_READ_JS to normalize items to objects","Retry after full hydration; placeholder rows often disappear once loaded","Log data.items to identify which entries are malformed"],"exampleFix":"// before\nfor (const row of data.items) {\n    if (!row || typeof row !== 'object') {\n        throw new CommandExecutionError(`${webHost} feed: malformed feed item`);\n    }\n// after\nfor (const row of data.items.filter(r => r && typeof r === 'object')) {\n    // skip malformed rows instead of aborting","handlingStrategy":"type-guard","validationCode":"const cleanItems = (data.items ?? []).filter(r => r && typeof r === 'object');","typeGuard":"function isFeedItem(row) { return !!row && typeof row === 'object' && !Array.isArray(row); }","tryCatchPattern":"try {\n  const rows = await runFeed(page, webHost, limit);\n} catch (err) {\n  if (err instanceof CommandExecutionError && err.message.includes('malformed feed item')) {\n    // filter/skip bad rows or refresh the page and retry\n  } else throw err;\n}","preventionTips":["Filter non-object rows client-side before mapping","Skip placeholder/ad/skeleton entries","Re-check item structure after site updates"],"tags":["feed","schema","data-quality"],"backgroundTag":"payload-schema-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}