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.
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 omitted requested eid
- Xiaoyuzhou playback progress returned duplicate eid
- Zhihu answer comment
- Zhihu pagination exceeded its fetch budget
- Zhihu pagination returned a malformed next URL
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9e7c437c2b39e39c.
Report an issue: GitHub.
Appendix: 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)