jackwener/OpenCLI · warning · EmptyResultError
rednote/comments
Error message
rednote/comments
What it means
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.
Source
Thrown at clis/rednote/comments.js:50
{ name: 'note-id', required: true, positional: true, help: 'Full rednote note URL with xsec_token' },
{ name: 'limit', type: 'int', default: 20, help: 'Number of top-level comments (max 50)' },
{ name: 'with-replies', type: 'boolean', default: false, help: 'Include nested replies; reply_to is the direct target shown by the page' },
],
columns: ['rank', 'author', 'text', 'likes', 'time', 'is_reply', 'reply_to', 'images'],
func: async (page, kwargs) => {
const limit = parseCommentLimit(kwargs.limit);
const withReplies = Boolean(kwargs['with-replies']);
const raw = String(kwargs['note-id']);
const noteId = parseNoteId(raw);
await page.goto(buildNoteUrl(raw, {
commandName: 'rednote comments',
cookieRoot: 'rednote.com',
signedUrlHint: REDNOTE_SIGNED_URL_HINT,
}));
await page.wait({ time: 2 + Math.random() * 3 });
const data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));
if (!data || typeof data !== 'object') {
throw new EmptyResultError('rednote/comments', 'Unexpected evaluate response');
}
if (data.securityBlock) {
throw new CommandExecutionError('Rednote security block: the note detail page was blocked by risk control.', /^https?:\/\//.test(raw)
? 'The page may be temporarily restricted. Try again later or from a different session.'
: 'Try using a full URL from search results (with xsec_token) instead of a bare note ID.');
}
if (data.loginWall) {
throw new AuthRequiredError('www.rednote.com', 'Note comments require login');
}
void noteId;
const all = normalizeCommentRows(data.results, 'rednote/comments');
const toRow = (c, i) => ({
rank: i + 1,
author: c.author,
text: c.text,
likes: c.likes,
time: c.time,
is_reply: c.is_reply,View on GitHub (pinned to 49907e53dc)
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.
Example fix
// before (single fast evaluate)
await page.wait({ time: 2 + Math.random() * 3 });
const data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));
// after (retry once on empty response)
let data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));
if (!data || typeof data !== 'object') {
await page.wait(5);
data = await page.evaluate(buildCommentsExtractJs(withReplies, limit));
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check the URL shape before invoking the command
function isFullRednoteNoteUrl(u) {
return /^https?:\/\/www\.rednote\.com\/(explore|discovery\/item)\/[0-9a-f]+.*xsec_token=/.test(u);
}
if (!isFullRednoteNoteUrl(noteUrl)) throw new Error('Use a full rednote.com note URL including xsec_token'); Type guard
function isEvaluateResponse(d) {
return typeof d === 'object' && d !== null
&& Array.isArray(d.results)
&& d.securityBlock === undefined && d.loginWall === undefined;
} Try / catch
try {
const rows = await run(['rednote', 'comments', noteUrl, '--limit', '20']);
} catch (err) {
if (err instanceof EmptyResultError && /Unexpected evaluate response/.test(err.message)) {
await sleep(3000); // transient load/navigation often resolves it
return run(['rednote', 'comments', noteUrl, '--limit', '20']);
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- antigravity copy-message
- chatgpt detail
- Failed to export generated ChatGPT image assets
- chatgpt project-list
- chatgpt read
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/848e33411eb4f5f5.
Report an issue: GitHub.