jackwener/OpenCLI · error · CommandExecutionError

${commandName}: malformed comment row is_reply

Error message

${commandName}: malformed comment row is_reply

What it means

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.

Source

Thrown at clis/xiaohongshu/comments.js:124

    if (value == null)
        return [];
    if (!Array.isArray(value)) {
        throw new CommandExecutionError(`${commandName}: malformed comments payload`);
    }
    return value.map((row, index) => {
        if (!row || typeof row !== 'object' || Array.isArray(row)) {
            throw new CommandExecutionError(`${commandName}: malformed comment row at index ${index}`);
        }
        const text = normalizeOptionalString(row.text, 'text', commandName);
        if (!text) {
            throw new CommandExecutionError(`${commandName}: malformed comment row text`);
        }
        const likes = Number(row.likes);
        if (!Number.isInteger(likes) || likes < 0) {
            throw new CommandExecutionError(`${commandName}: malformed comment row likes`);
        }
        if (typeof row.is_reply !== 'boolean') {
            throw new CommandExecutionError(`${commandName}: malformed comment row is_reply`);
        }
        return {
            author: normalizeOptionalString(row.author, 'author', commandName),
            authorHrefRaw: normalizeOptionalString(row.authorHrefRaw, 'authorHrefRaw', commandName),
            text,
            likes,
            time: normalizeOptionalString(row.time, 'time', commandName),
            is_reply: row.is_reply,
            reply_to: normalizeOptionalString(row.reply_to, 'reply_to', commandName),
            images: normalizeCommentImages(row.images, commandName),
        };
    });
}

/**
 * Host-agnostic IIFE that scrolls a note's comment list and extracts
 * top-level comments (and optionally nested 楼中楼 replies). Exported so
 * the rednote adapter can reuse the exact same selector chain.

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update buildCommentsExtractJs to always emit is_reply as a real boolean (Boolean(...))
  2. Pre-validate extractor output so each row.is_reply is typeof 'boolean'
  3. Default missing is_reply to false in normalizeCommentRows if rows lacking the flag should be treated as top-level comments
  4. Fix test fixtures/custom scripts to use boolean values

Example fix

// before
if (typeof row.is_reply !== 'boolean') {
    throw new CommandExecutionError(`${commandName}: malformed comment row is_reply`);
}
// after
const isReply = row.is_reply === undefined ? false : Boolean(row.is_reply);
Defensive patterns

Strategy: validation

Validate before calling

if (!rows.every(r => typeof r.is_reply === 'boolean')) throw new Error('row.is_reply must be a boolean');

Type guard

const hasValidIsReply = (row) => typeof row.is_reply === 'boolean';

Try / catch

try {
  const comments = await cli.comments(noteUrl);
} catch (err) {
  if (err.message.includes('malformed comment row is_reply')) {
    // refresh extractor or default missing flags to false
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/0702f50ccace2067. Report an issue: GitHub.