jackwener/OpenCLI · error · CommandExecutionError

Zhihu answer comments contained a malformed ${role} row

Error message

Zhihu answer comments contained a malformed ${role} row

What it means

CommandExecutionError thrown by describeComment when a comment row (root or child, per the role argument) is null, not an object, or an Array. The library validates each row from payload.data before extracting its id and reply relationships, so downstream code can trust the descriptor shape.

Source

Thrown at clis/zhihu/answer-comments-helpers.js:91

        }
        if (status === 401 || status === 403 || code === '40353' || payload.__needLogin) {
            throw new AuthRequiredError('www.zhihu.com', `Failed to fetch Zhihu ${label}`);
        }
        if (status === 404 && notFoundDetail) throw new EmptyResultError('zhihu answer-comments', notFoundDetail);
        if (status >= 400) throw new CommandExecutionError(`Zhihu ${label} request failed (HTTP ${status})`);
        throw new CommandExecutionError(`Zhihu ${label} returned an error payload: ${payload.__errorMessage || code}`);
    }
    if (!Array.isArray(payload.data) || !payload.paging || typeof payload.paging !== 'object') {
        throw new CommandExecutionError(`Zhihu ${label} returned a malformed payload`);
    }
    if (typeof payload.paging.is_end !== 'boolean') {
        throw new CommandExecutionError(`Zhihu ${label} returned malformed paging state`);
    }
    return payload;
}
function describeComment(comment, role, expectedRootId = '') {
    if (!comment || typeof comment !== 'object' || Array.isArray(comment)) {
        throw new CommandExecutionError(`Zhihu answer comments contained a malformed ${role} row`);
    }
    const id = commentId(comment.id);
    if (!id) throw new CommandExecutionError(`Zhihu answer comments contained a ${role} row without a stable id`);
    const rootId = role === 'root' ? id : commentId(comment.reply_root_comment_id);
    const parentId = role === 'root' ? '' : commentId(comment.reply_comment_id);
    if (role === 'child' && rootId !== expectedRootId) {
        throw new CommandExecutionError(`Zhihu answer comment ${id} had conflicting root provenance`);
    }
    if (role === 'child' && !parentId) {
        throw new CommandExecutionError(`Zhihu answer comment ${id} did not identify its immediate parent`);
    }
    const signature = JSON.stringify({
        role,
        rootId,
        parentId,
        author: memberName(comment.author),
        replyTo: role === 'child' ? memberName(comment.reply_to_author) : '',
        content: stripHtml(comment.content || ''),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Filter out non-object rows before processing: data.filter(c => c && typeof c === 'object' && !Array.isArray(c))
  2. Handle deleted comments (null rows) by skipping them rather than failing the whole fetch
  3. Log the offending row with -v to check for API schema changes
  4. Update describeComment/parsing if Zhihu changed the row shape

Example fix

// before
payload.data.forEach(c => describeComment(c, 'root')); // throws on null placeholder rows
// after
payload.data.filter(c => c && typeof c === 'object' && !Array.isArray(c))
  .forEach(c => describeComment(c, 'root'));
Defensive patterns

Strategy: type-guard

Validate before calling

const rows = (payload.data || []).filter(c => c && typeof c === 'object' && !Array.isArray(c));

Type guard

function isCommentRow(c){ return !!c && typeof c === 'object' && !Array.isArray(c) && typeof c.id !== 'undefined'; }

Try / catch

try { return describeComment(row, role, rootId); } catch (e) { if (/malformed .* row/.test(e.message)) { log(`skipping bad row: ${JSON.stringify(row)}`); return null; } throw e; }

Prevention

When it happens

Trigger: An entry in payload.data (or a nested child in reply list) is null, a primitive, or an array — e.g. Zhihu inserting null placeholders for deleted comments, or a schema change altering row structure.

Common situations: Deleted/removed comments serialized as null in the data array; API returning flattened rows after a schema change; children embedded differently than expected.

Understand the failure class

Related errors


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