{"record":{"id":"848e33411eb4f5f5","repo":"jackwener/OpenCLI","slug":"rednote-comments","errorCode":null,"errorMessage":"rednote/comments","messagePattern":"rednote/comments","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/rednote/comments.js","lineNumber":50,"sourceCode":"        { name: 'note-id', required: true, positional: true, help: 'Full rednote note URL with xsec_token' },\n        { name: 'limit', type: 'int', default: 20, help: 'Number of top-level comments (max 50)' },\n        { name: 'with-replies', type: 'boolean', default: false, help: 'Include nested replies; reply_to is the direct target shown by the page' },\n    ],\n    columns: ['rank', 'author', 'text', 'likes', 'time', 'is_reply', 'reply_to', 'images'],\n    func: async (page, kwargs) => {\n        const limit = parseCommentLimit(kwargs.limit);\n        const withReplies = Boolean(kwargs['with-replies']);\n        const raw = String(kwargs['note-id']);\n        const noteId = parseNoteId(raw);\n        await page.goto(buildNoteUrl(raw, {\n            commandName: 'rednote comments',\n            cookieRoot: 'rednote.com',\n            signedUrlHint: REDNOTE_SIGNED_URL_HINT,\n        }));\n        await page.wait({ time: 2 + Math.random() * 3 });\n        const data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));\n        if (!data || typeof data !== 'object') {\n            throw new EmptyResultError('rednote/comments', 'Unexpected evaluate response');\n        }\n        if (data.securityBlock) {\n            throw new CommandExecutionError('Rednote security block: the note detail page was blocked by risk control.', /^https?:\\/\\//.test(raw)\n                ? 'The page may be temporarily restricted. Try again later or from a different session.'\n                : 'Try using a full URL from search results (with xsec_token) instead of a bare note ID.');\n        }\n        if (data.loginWall) {\n            throw new AuthRequiredError('www.rednote.com', 'Note comments require login');\n        }\n        void noteId;\n        const all = normalizeCommentRows(data.results, 'rednote/comments');\n        const toRow = (c, i) => ({\n            rank: i + 1,\n            author: c.author,\n            text: c.text,\n            likes: c.likes,\n            time: c.time,\n            is_reply: c.is_reply,","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rednote/comments.js#L32-L68","documentation":"After navigating to the note page, the command evaluates buildCommentsExtractJs in the page. If the script returns null/undefined or a non-object (instead of the expected {results, ...} envelope), the command throws EmptyResultError('rednote/comments', 'Unexpected evaluate response') — the extraction could not produce any structured payload at all.","triggerScenarios":"page.evaluate returns undefined because the IIFE threw internally, the comments DOM root is absent (note deleted/region-locked), the page was replaced by an error/redirect interstitial, or the extraction script timed out / was interrupted before returning. Distinct from securityBlock/loginWall, which return structured flags — this fires only when there is no object at all.","commonSituations":"Rednote DOM restructuring breaking the extraction script so it throws; note URLs that 404 or redirect to a region-unavailable page; very slow loads where the 2–5s wait was insufficient and the script ran against an empty document; headless-detection pages serving no real content.","solutions":["Re-run the command — transient navigation or slow load often resolves on retry.","Confirm the note URL is a full rednote.com note URL with a valid xsec_token (bare/expired links often land on error pages with no comments DOM).","Increase effective wait/retry the navigation if the page loads slowly.","Log in via the rednote auth flow — some notes require a session before the comments DOM renders.","Check for a Rednote markup change and update buildCommentsExtractJs (clis/xiaohongshu/comments.js) selectors if the page layout changed."],"exampleFix":"// before (single fast evaluate)\nawait page.wait({ time: 2 + Math.random() * 3 });\nconst data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));\n// after (retry once on empty response)\nlet data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));\nif (!data || typeof data !== 'object') {\n  await page.wait(5);\n  data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));\n}","handlingStrategy":"retry","validationCode":"// pre-check the URL shape before invoking the command\nfunction isFullRednoteNoteUrl(u) {\n  return /^https?:\\/\\/www\\.rednote\\.com\\/(explore|discovery\\/item)\\/[0-9a-f]+.*xsec_token=/.test(u);\n}\nif (!isFullRednoteNoteUrl(noteUrl)) throw new Error('Use a full rednote.com note URL including xsec_token');","typeGuard":"function isEvaluateResponse(d) {\n  return typeof d === 'object' && d !== null\n    && Array.isArray(d.results)\n    && d.securityBlock === undefined && d.loginWall === undefined;\n}","tryCatchPattern":"try {\n  const rows = await run(['rednote', 'comments', noteUrl, '--limit', '20']);\n} catch (err) {\n  if (err instanceof EmptyResultError && /Unexpected evaluate response/.test(err.message)) {\n    await sleep(3000);           // transient load/navigation often resolves it\n    return run(['rednote', 'comments', noteUrl, '--limit', '20']);\n  }\n  throw err;\n}","preventionTips":["Retry once on EmptyResultError — transient navigation/slow loads are the most common cause.","Always pass full note URLs with a fresh xsec_token, never bare note IDs.","Ensure the rednote session is logged in; some notes render no comments DOM anonymously.","Allow generous page-load time before extraction; slow loads leave the DOM empty.","If it persists across notes, the page markup likely changed — update the extraction script selectors."],"tags":["empty-result","browser-automation","rednote","dom-extraction"],"backgroundTag":"empty-scrape-result","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}