jackwener/OpenCLI · error · CommandExecutionError

Zhihu answer comments returned conflicting data for comment

Error message

Zhihu answer comments returned conflicting data for comment ${descriptor.id}

What it means

addPageComments deduplicates comments by id across pages. If the same comment id appears twice with a different signature (JSON of role, rootId, parentId, author, etc.), the API is serving contradictory data for one comment, so the library throws rather than silently choosing one version.

Source

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

        role,
        rootId,
        parentId,
        author: memberName(comment.author),
        replyTo: role === 'child' ? memberName(comment.reply_to_author) : '',
        content: stripHtml(comment.content || ''),
    });
    return { id, rootId, parentId, signature };
}
function addPageComments(byId, comments, role, expectedRootId) {
    for (const comment of comments) {
        const descriptor = describeComment(comment, role, expectedRootId);
        const previous = byId.get(descriptor.id);
        if (!previous) {
            byId.set(descriptor.id, { comment, descriptor });
            continue;
        }
        if (previous.descriptor.signature !== descriptor.signature) {
            throw new CommandExecutionError(`Zhihu answer comments returned conflicting data for comment ${descriptor.id}`);
        }
        const oldCount = previous.comment.child_comment_count;
        const newCount = comment.child_comment_count;
        if (Number.isInteger(newCount) && (!Number.isInteger(oldCount) || newCount > oldCount)) {
            previous.comment = { ...previous.comment, child_comment_count: newCount };
        }
    }
}
async function fetchPages(page, options) {
    const { firstUrl, limit, label, role, expectedRootId = '', normalizeNext, notFoundDetail = '' } = options;
    const byId = new Map();
    const visited = new Set();
    const maxPages = Math.ceil(limit / PAGE_SIZE) + PAGE_OVERLAP_ALLOWANCE;
    let pageCount = 0;
    let url = firstUrl;
    while (byId.size < limit) {
        if (visited.has(url)) throw new CommandExecutionError(`Zhihu ${label} pagination returned a repeated next URL`);
        if (pageCount >= maxPages) throw new CommandExecutionError(`Zhihu ${label} pagination exceeded its fetch budget`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Refetch all pages quickly in one run so all copies of the comment come from the same snapshot.
  2. Disable or bypass intermediate caches/proxies that can serve mixed-age pages.
  3. If live edits are the cause, accept it as transient and retry; or downgrade to a page-size/order that fetches in a single page.
  4. If you need edit-tolerance, patch addPageComments to compare only identity-critical signature fields.

Example fix

// before: comparing full signature (author/content included)
if (previous.descriptor.signature !== descriptor.signature) throw ...;
// after: tolerate content-only edits
const stable = d => JSON.stringify({ role: d.role, rootId: d.rootId, parentId: d.parentId });
if (stable(previous.descriptor) !== stable(descriptor)) throw ...;
Defensive patterns

Strategy: retry

Validate before calling

// detect cross-page duplicates with differing payloads before they reach the library
function scanForConflicts(pages) {
  const seen = new Map();
  for (const page of pages) for (const c of page.data) {
    const key = String(c.id);
    const snap = JSON.stringify({ a: c.author, p: c.reply_comment_id });
    if (seen.has(key) && seen.get(key) !== snap) return key;
    seen.set(key, snap);
  }
  return null;
}

Try / catch

try {
  const comments = await fetchRootComments(page, answerId, order, limit);
} catch (err) {
  if (String(err.message).includes('returned conflicting data')) {
    await sleep(2000); // let replicas converge / snapshot stabilize
    return fetchRootComments(page, answerId, order, limit);
  }
  throw err;
}

Prevention

When it happens

Trigger: Two pagination pages both contain comment X, but its fields (author name, content, parent links) differ between occurrences — detected via descriptor.signature inequality in addPageComments.

Common situations: Live comment edited between page fetches (author renamed, content changed), load-balanced API replicas serving different snapshots, or cache layers mixing old and new responses. Note: a merely larger child_comment_count is tolerated, so this fires only for other field changes.

Related errors


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