{"record":{"id":"0acf918d0206511f","repo":"jackwener/OpenCLI","slug":"commandname-malformed-comments-payload","errorCode":null,"errorMessage":"${commandName}: malformed comments payload","messagePattern":"(.+?): malformed comments payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/comments.js","lineNumber":109,"sourceCode":"        }\n        catch {\n            throw new CommandExecutionError(`${commandName}: malformed comment row image URL`);\n        }\n        if ((parsed.protocol !== 'https:' && parsed.protocol !== 'http:') || parsed.username || parsed.password) {\n            throw new CommandExecutionError(`${commandName}: malformed comment row image URL`);\n        }\n        const href = parsed.toString();\n        if (!urls.includes(href))\n            urls.push(href);\n    }\n    return urls;\n}\n\nexport function normalizeCommentRows(value, commandName = 'xiaohongshu/comments') {\n    if (value == null)\n        return [];\n    if (!Array.isArray(value)) {\n        throw new CommandExecutionError(`${commandName}: malformed comments payload`);\n    }\n    return value.map((row, index) => {\n        if (!row || typeof row !== 'object' || Array.isArray(row)) {\n            throw new CommandExecutionError(`${commandName}: malformed comment row at index ${index}`);\n        }\n        const text = normalizeOptionalString(row.text, 'text', commandName);\n        if (!text) {\n            throw new CommandExecutionError(`${commandName}: malformed comment row text`);\n        }\n        const likes = Number(row.likes);\n        if (!Number.isInteger(likes) || likes < 0) {\n            throw new CommandExecutionError(`${commandName}: malformed comment row likes`);\n        }\n        if (typeof row.is_reply !== 'boolean') {\n            throw new CommandExecutionError(`${commandName}: malformed comment row is_reply`);\n        }\n        return {\n            author: normalizeOptionalString(row.author, 'author', commandName),","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/comments.js#L91-L127","documentation":"normalizeCommentRows is the entry normalizer for scraped comments. The whole payload must be an array (null/undefined is treated as empty). A non-array payload is rejected with CommandExecutionError as a malformed comments payload.","triggerScenarios":"page.evaluate or an API wrapper returned an object/string/undefined instead of an array of comment rows.","commonSituations":"XHS comment section structure changed, the comment container selector matched nothing and the script returned null wrapped in an object, or the caller passed a { comments: [...] } envelope without unwrapping.","solutions":["Unwrap envelopes before calling: pass payload.comments, not the envelope object.","Log the raw payload to see what shape is actually returned.","Check that the comments container loaded (wait for the selector) before extraction.","If the payload is legitimately absent, pass null/undefined instead of an empty object, which is accepted as []."],"exampleFix":"// before\nnormalizeCommentRows(await fetchComments(page), cmd);\n// after\nconst raw = await fetchComments(page);\nnormalizeCommentRows(Array.isArray(raw) ? raw : raw?.comments ?? null, cmd);","handlingStrategy":"type-guard","validationCode":"const raw = await fetchComments(page);\nif (raw != null && !Array.isArray(raw)) {\n  throw new Error(`Comments payload is ${typeof raw}, expected array`);\n}","typeGuard":"function isCommentPayload(v) {\n  return v == null || (Array.isArray(v) && v.every(r => r && typeof r === 'object' && !Array.isArray(r)));\n}","tryCatchPattern":"try {\n  comments = normalizeCommentRows(raw, cmd);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /malformed comments payload/.test(e.message)) {\n    console.error('Payload shape:', typeof raw, raw && Object.keys(raw));\n    comments = [];\n  } else throw e;\n}","preventionTips":["Unwrap envelope objects ({comments:[...]}) before normalizing.","Ensure the comment section fully rendered before extraction.","Log raw payload types on failure to catch XHS format changes.","Pass null/undefined (accepted as empty) rather than {} when there are no comments."],"tags":["validation","scraping","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}