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
- Refetch all pages quickly in one run so all copies of the comment come from the same snapshot.
- Disable or bypass intermediate caches/proxies that can serve mixed-age pages.
- 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.
- 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
- Fetch all pages in one fast run to minimize mid-fetch edits.
- Prefer a single-page fetch when the comment count fits in PAGE_SIZE.
- Bypass caches for comment endpoints to avoid mixed-age snapshots.
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
- Xiaoyuzhou playback progress returned duplicate eid ${eid}
- Xiaoyuzhou playback progress omitted requested eid ${episode
- Zhihu answer comment ${id} had conflicting root provenance
- Zhihu ${label} pagination returned a repeated next URL
- Zhihu ${label} pagination exceeded its fetch budget
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9e7c437c2b39e39c.
Report an issue: GitHub.