jackwener/OpenCLI · error · CommandExecutionError
${commandName}: malformed comment row text
Error message
${commandName}: malformed comment row text What it means
normalizeCommentRows validates each row returned by the in-page comments extractor. When a row is an object but its text field normalizes to empty/missing (normalizeOptionalString returns falsy), the command rejects it because a comment without text is useless downstream. The commandName ('xiaohongshu/comments') is interpolated into the message.
Source
Thrown at clis/xiaohongshu/comments.js:117
if (!urls.includes(href))
urls.push(href);
}
return urls;
}
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
- Inspect data.results from the extractor and drop rows with empty/whitespace text before normalizing
- Update buildCommentsExtractJs selectors to correctly capture comment text for the current Xiaohongshu DOM
- Filter malformed rows at the call site in normalizeCommentRows (skip instead of throw) if partial results are acceptable
- Retry the scrape — a transient render may have produced empty text nodes
Example fix
// before
const text = normalizeOptionalString(row.text, 'text', commandName);
if (!text) {
throw new CommandExecutionError(`${commandName}: malformed comment row text`);
}
// after
const text = normalizeOptionalString(row.text, 'text', commandName);
if (!text) {
return null; // filter out empty rows instead of failing the whole command
} Defensive patterns
Strategy: validation
Validate before calling
function isValidCommentRows(rows) {
return Array.isArray(rows) && rows.every(r => r && typeof r === 'object'
&& typeof r.text === 'string' && r.text.trim() !== '');
}
if (!isValidCommentRows(data.results)) throw new Error('extractor returned rows without text'); Type guard
const hasText = (row) => typeof row === 'object' && row !== null && typeof row.text === 'string' && row.text.trim().length > 0;
Try / catch
try {
const comments = await cli.comments(noteUrl, { limit: 20 });
} catch (err) {
if (err.message.includes('malformed comment row text')) {
// retry or fall back to partial handling
} else throw err;
} Prevention
- Keep buildCommentsExtractJs selectors updated against the live Xiaohongshu DOM
- Filter empty-text rows in the extractor before returning
- Add integration tests with real page fixtures
When it happens
Trigger: The page.evaluate extractor returned a results array containing a row object whose text is null, undefined, an empty string, or only whitespace (normalizeOptionalString trims).
Common situations: Xiaohongshu DOM changes so the extractor's text selector matches an empty node; comments deleted by the author leave empty placeholders; custom/patched extract JS passed via buildCommentsExtractJs emits rows without text.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ${commandName}: malformed comment row likes
- ${commandName}: malformed comment row is_reply
- ${label} did not include a stable numeric id.
- ${label} did not include a stable text value.
- ${label} returned an unexpected payload shape; expected an o
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2861cda0e0c1e0c8.
Report an issue: GitHub.