{"record":{"id":"533548625ca55f87","repo":"jackwener/OpenCLI","slug":"zhihu-label-returned-malformed-paging-state","errorCode":null,"errorMessage":"Zhihu ${label} returned malformed paging state","messagePattern":"Zhihu (.+?) returned malformed paging state","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/zhihu/answer-comments-helpers.js","lineNumber":85,"sourceCode":"    if (status >= 400 || code || payload.__errorMessage || payload.__needLogin) {\n        if (code === '40362') {\n            throw new CommandExecutionError(\n                `Zhihu risk control blocked ${label} (40362): ${payload.__errorMessage || 'abnormal request'}`,\n                'Open the answer in the connected Chrome profile and retry later.',\n            );\n        }\n        if (status === 401 || status === 403 || code === '40353' || payload.__needLogin) {\n            throw new AuthRequiredError('www.zhihu.com', `Failed to fetch Zhihu ${label}`);\n        }\n        if (status === 404 && notFoundDetail) throw new EmptyResultError('zhihu answer-comments', notFoundDetail);\n        if (status >= 400) throw new CommandExecutionError(`Zhihu ${label} request failed (HTTP ${status})`);\n        throw new CommandExecutionError(`Zhihu ${label} returned an error payload: ${payload.__errorMessage || code}`);\n    }\n    if (!Array.isArray(payload.data) || !payload.paging || typeof payload.paging !== 'object') {\n        throw new CommandExecutionError(`Zhihu ${label} returned a malformed payload`);\n    }\n    if (typeof payload.paging.is_end !== 'boolean') {\n        throw new CommandExecutionError(`Zhihu ${label} returned malformed paging state`);\n    }\n    return payload;\n}\nfunction describeComment(comment, role, expectedRootId = '') {\n    if (!comment || typeof comment !== 'object' || Array.isArray(comment)) {\n        throw new CommandExecutionError(`Zhihu answer comments contained a malformed ${role} row`);\n    }\n    const id = commentId(comment.id);\n    if (!id) throw new CommandExecutionError(`Zhihu answer comments contained a ${role} row without a stable id`);\n    const rootId = role === 'root' ? id : commentId(comment.reply_root_comment_id);\n    const parentId = role === 'root' ? '' : commentId(comment.reply_comment_id);\n    if (role === 'child' && rootId !== expectedRootId) {\n        throw new CommandExecutionError(`Zhihu answer comment ${id} had conflicting root provenance`);\n    }\n    if (role === 'child' && !parentId) {\n        throw new CommandExecutionError(`Zhihu answer comment ${id} did not identify its immediate parent`);\n    }\n    const signature = JSON.stringify({","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/zhihu/answer-comments-helpers.js#L67-L103","documentation":"CommandExecutionError thrown when payload.paging exists but paging.is_end is not a boolean. The pagination loop relies on is_end to know when to stop fetching pages; without a definitive boolean it cannot terminate safely, so the library refuses to continue.","triggerScenarios":"The Zhihu comment response's paging object omitted is_end or typed it as something else (string 'true', number, undefined) — a schema deviation on the pagination metadata.","commonSituations":"Zhihu changing pagination metadata format; last-page responses omitting is_end; paginated endpoints for new content types behaving differently.","solutions":["Inspect paging with -v to see what fields Zhihu now returns","Coerce defensively: treat missing is_end as false only when next link is absent, otherwise stop after N pages as a safeguard","Update the parser if Zhihu renamed/moved the field (e.g. paging.is_end -> another key)","Add a max-page cap in your loop so any pagination anomaly terminates the fetch"],"exampleFix":"// before\nwhile (!done) { const p = await fetchCommentPage(url); done = p.paging.is_end; } // throws on non-boolean\n// after\nlet pages = 0;\nwhile (!done && pages++ < 50) { const p = await fetchCommentPage(url); done = p.paging?.is_end === true || !p.paging?.next; }","handlingStrategy":"validation","validationCode":"const body = await res.json(); if (typeof body?.paging?.is_end !== 'boolean') throw new Error('paging.is_end missing/non-boolean: ' + JSON.stringify(body?.paging));","typeGuard":"function hasValidPaging(p){ return typeof p?.paging?.is_end === 'boolean'; }","tryCatchPattern":"try { await fetchCommentPage(url); } catch (e) { if (/malformed paging/.test(e.message)) { /* stop paginating with a safe default or inspect paging keys */ } throw e; }","preventionTips":["Always cap pagination loops with a max-page limit","Treat missing is_end as end-of-pages when no next link exists","Log the paging object when pagination behavior changes","Add an assertion test on paging metadata shape"],"tags":["zhihu","pagination","schema-validation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}