jackwener/OpenCLI · error · CommandExecutionError

${commandName}: malformed comment row likes

Error message

${commandName}: malformed comment row likes

What it means

normalizeCommentRows requires each comment row to carry a non-negative integer likes count. It coerces row.likes with Number() and throws if the result is not an integer or is negative. This guarantees the normalized row shape consumed by the CLI output.

Source

Thrown at clis/xiaohongshu/comments.js:121

}

export function normalizeCommentRows(value, commandName = 'xiaohongshu/comments') {
    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),
        };
    });
}

/**

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Fix buildCommentsExtractJs to coerce like counts ('1.2k' -> 1200, missing -> 0) before returning rows
  2. Pre-validate the extractor output: ensure every row.likes is a non-negative integer
  3. Add a defensive default in normalizeCommentRows (treat missing likes as 0) if the shape permits
  4. Retry the scrape if the count element had not finished rendering

Example fix

// before
const likes = Number(row.likes);
// after
const rawLikes = String(row.likes ?? '').trim().toLowerCase();
const likes = /^\d+(\.\d+)?k$/.test(rawLikes)
    ? Math.round(parseFloat(rawLikes) * 1000)
    : Number(rawLikes);
Defensive patterns

Strategy: validation

Validate before calling

const toInt = v => { const n = Number(v); return Number.isInteger(n) && n >= 0 ? n : null; };
if (!rows.every(r => toInt(r.likes) !== null)) throw new Error('row.likes must be a non-negative integer');

Type guard

const hasValidLikes = (row) => { const n = Number(row.likes); return Number.isInteger(n) && n >= 0; };

Try / catch

try {
  const comments = await cli.comments(noteUrl);
} catch (err) {
  if (err.message.includes('malformed comment row likes')) {
    // treat as extractor/DOM mismatch; retry or report
  } else throw err;
}

Prevention

When it happens

Trigger: row.likes is undefined, null, a non-numeric string, a float, NaN, or a negative number such that Number(row.likes) fails the Number.isInteger/likes>=0 check.

Common situations: Xiaohongshu renders 'like' or '赞' instead of a number for zero-like comments so the extractor yields a non-numeric string; extractor grabs a formatted count like '1.2k'; DOM changes move the like-count element.

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/a1288df800fdd147. Report an issue: GitHub.