{"record":{"id":"1c70d5865bcdd7cc","repo":"jackwener/OpenCLI","slug":"zhihu-answer-root-comment-id-had-malformed-chil","errorCode":null,"errorMessage":"Zhihu answer root comment ${id} had malformed child count","messagePattern":"Zhihu answer root comment (.+?) had malformed child count","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/zhihu/answer-comments-helpers.js","lineNumber":184,"sourceCode":"}\nasync function fetchChildComments(page, rootId, limit) {\n    const path = `/api/v4/comment_v5/comment/${rootId}/child_comment`;\n    return fetchPages(page, {\n        firstUrl: `https://www.zhihu.com${path}?limit=${PAGE_SIZE}&offset=0`,\n        limit,\n        label: 'answer child comments',\n        role: 'child',\n        expectedRootId: rootId,\n        normalizeNext: (next) => normalizePageUrl(next, path, { limit: String(PAGE_SIZE), offset: null }),\n    });\n}\nexport async function fetchRepliesByRoot(page, roots, repliesLimit) {\n    const repliesByRoot = new Map();\n    if (repliesLimit === 0) return repliesByRoot;\n    for (const root of roots) {\n        const id = describeComment(root, 'root').id;\n        if (!Number.isInteger(root.child_comment_count) || root.child_comment_count < 0) {\n            throw new CommandExecutionError(`Zhihu answer root comment ${id} had malformed child count`);\n        }\n        if (root.child_comment_count === 0) continue;\n        const children = await fetchChildComments(page, id, repliesLimit);\n        if (children.length === 0) {\n            throw new CommandExecutionError(`Zhihu answer root comment ${id} advertised replies but returned none`);\n        }\n        repliesByRoot.set(id, children);\n    }\n    return repliesByRoot;\n}\nfunction resolveDepths(rootId, childrenById) {\n    const depths = new Map();\n    for (const childId of childrenById.keys()) {\n        if (depths.has(childId)) continue;\n        const chain = [];\n        const active = new Set();\n        let cursor = childId;\n        let depth = 0;","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/zhihu/answer-comments-helpers.js#L166-L202","documentation":"fetchRepliesByRoot validates each root comment's child_comment_count before deciding whether to fetch its replies. A root whose count is missing or not a non-negative integer makes downstream loop/budget logic unreliable, so the library throws with the root's id.","triggerScenarios":"A root_comment row from /root_comment has child_comment_count undefined, null, a non-integer (float/string), or a negative number.","commonSituations":"Zhihu schema drift renaming the field (e.g. to child_count), API returning partial rows for very old comments, or mock fixtures built from an older API version lacking the field.","solutions":["Inspect the root row: check whether child_comment_count exists and is a plain integer.","Refresh the fixture/mock to match the current API response shape.","Update the library if Zhihu renamed or retyped the count field.","Refetch — if only one root is malformed it may be a transient partial response."],"exampleFix":"// before: fixture from old API\n{ id: 'r1', child_count: 3 }\n// after\n{ id: 'r1', child_comment_count: 3 }","handlingStrategy":"validation","validationCode":"// validate root rows before processing\nfunction rootsHaveValidCounts(roots) {\n  return roots.every(r => Number.isInteger(r?.child_comment_count) && r.child_comment_count >= 0);\n}","typeGuard":"function hasValidChildCount(root) {\n  return Number.isInteger(root?.child_comment_count) && root.child_comment_count >= 0;\n}","tryCatchPattern":"try {\n  const byRoot = await fetchRepliesByRoot(page, roots, repliesLimit);\n} catch (err) {\n  const m = String(err.message).match(/root comment (\\d+) had malformed child count/);\n  if (m) {\n    console.warn(`Skipping root ${m[1]} with malformed child_comment_count`);\n    return fetchRepliesByRoot(page, roots.filter(r => String(r.id) !== m[1]), repliesLimit);\n  }\n  throw err;\n}","preventionTips":["Regenerate test fixtures from live API responses whenever the schema may have changed.","Coerce counts defensively at ingestion if you own the raw rows (Number(...) + isInteger check).","Track Zhihu API changelogs for field renames like child_comment_count."],"tags":["api","data-validation","zhihu","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}