{"record":{"id":"0702f50ccace2067","repo":"jackwener/OpenCLI","slug":"commandname-malformed-comment-row-is-reply","errorCode":null,"errorMessage":"${commandName}: malformed comment row is_reply","messagePattern":"(.+?): malformed comment row is_reply","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/comments.js","lineNumber":124,"sourceCode":"    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),\n            authorHrefRaw: normalizeOptionalString(row.authorHrefRaw, 'authorHrefRaw', commandName),\n            text,\n            likes,\n            time: normalizeOptionalString(row.time, 'time', commandName),\n            is_reply: row.is_reply,\n            reply_to: normalizeOptionalString(row.reply_to, 'reply_to', commandName),\n            images: normalizeCommentImages(row.images, commandName),\n        };\n    });\n}\n\n/**\n * Host-agnostic IIFE that scrolls a note's comment list and extracts\n * top-level comments (and optionally nested 楼中楼 replies). Exported so\n * the rednote adapter can reuse the exact same selector chain.","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/comments.js#L106-L142","documentation":"normalizeCommentRows requires row.is_reply to be a strict boolean so downstream code can distinguish replies from top-level comments. Any other type (undefined, 0, 'true', null) triggers this error.","triggerScenarios":"The extractor emitted a row where is_reply is missing or not a literal boolean — e.g. the reply-detection logic in buildCommentsExtractJs failed to classify a comment under the current DOM.","commonSituations":"Xiaohongshu changes reply/indent markup so the reply flag is never set; manually crafted test data uses truthy values like 1 or 'true'; rows produced by a custom extract script omit the field.","solutions":["Update buildCommentsExtractJs to always emit is_reply as a real boolean (Boolean(...))","Pre-validate extractor output so each row.is_reply is typeof 'boolean'","Default missing is_reply to false in normalizeCommentRows if rows lacking the flag should be treated as top-level comments","Fix test fixtures/custom scripts to use boolean values"],"exampleFix":"// before\nif (typeof row.is_reply !== 'boolean') {\n    throw new CommandExecutionError(`${commandName}: malformed comment row is_reply`);\n}\n// after\nconst isReply = row.is_reply === undefined ? false : Boolean(row.is_reply);","handlingStrategy":"validation","validationCode":"if (!rows.every(r => typeof r.is_reply === 'boolean')) throw new Error('row.is_reply must be a boolean');","typeGuard":"const hasValidIsReply = (row) => typeof row.is_reply === 'boolean';","tryCatchPattern":"try {\n  const comments = await cli.comments(noteUrl);\n} catch (err) {\n  if (err.message.includes('malformed comment row is_reply')) {\n    // refresh extractor or default missing flags to false\n  } else throw err;\n}","preventionTips":["Always emit Boolean(...) for flags in extract scripts","Use literals, not truthy values, in test fixtures","Re-verify reply-detection markup after Xiaohongshu UI updates"],"tags":["validation","scraping","data-shape","boolean"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}