jackwener/OpenCLI · error · TimeoutError
xiaohongshu search content
Error message
xiaohongshu search content
What it means
The `xiaohongshu search` command opens a headless browser, navigates to xiaohongshu.com/search_result, and waits up to CONTENT_WAIT_SECONDS for search results to render. The browser-side wait script returns 'timeout' when the expected content never appears, and collectSearchHarvest translates that into a TimeoutError. This usually means the page rendered something other than the expected search feed (login wall, security check, blank/collapsed render) or the site DOM/behavior changed.
Source
Thrown at clis/xiaohongshu/search.js:795
stopReason,
elapsedMs,
securityBlock,
},
};
})()
`;
}
async function collectSearchHarvest(page, limit, requestedFilters) {
const waitResult = unwrapEvaluateResult(await page.evaluate(WAIT_FOR_CONTENT_JS));
if (waitResult === 'login_wall') {
throw new AuthRequiredError('www.xiaohongshu.com', 'Xiaohongshu search results are blocked behind a login wall');
}
if (waitResult === 'security_block') {
throw new CliError('SECURITY_BLOCK', 'Xiaohongshu search was blocked by request-frequency or security controls.', 'Wait before retrying or use a different logged-in browser session.');
}
if (waitResult === 'timeout') {
throw new TimeoutError('xiaohongshu search content', CONTENT_WAIT_SECONDS);
}
if (waitResult !== 'content') {
throw new CommandExecutionError('Unexpected Xiaohongshu search wait payload shape.');
}
requireFilterApplication(await page.evaluate(buildApplySearchFiltersJs(requestedFilters)));
const harvestOptions = harvestOptionsForLimit(limit);
const harvest = requireHarvestPayload(await page.evaluate(buildScrollHarvestJs('www.xiaohongshu.com', limit, harvestOptions)), 'www.xiaohongshu.com');
if (harvest.diag.securityBlock) {
throw new CliError('SECURITY_BLOCK', 'Xiaohongshu search was blocked by request-frequency or security controls.', 'Wait before retrying or use a different logged-in browser session.');
}
return harvest;
}
async function replaceCollapsedTab(page, url) {
if (typeof page.getActivePage !== 'function' || typeof page.newTab !== 'function' ||
typeof page.setActivePage !== 'function' || typeof page.selectTab !== 'function' ||
typeof page.closeTab !== 'function') {
throw new CommandExecutionError(View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command once — transient slow rendering is the most common cause.
- Wait longer between invocations or run at an off-peak time so Xiaohongshu serves results without throttling.
- Verify in a real browser that the same search URL renders normal results; if a login wall or security banner shows, authenticate the browser session (cookies) first.
- If it reproduces consistently, the site layout likely changed — update the wait/content detection selectors in WAIT_FOR_CONTENT_JS.
Example fix
// before
await page.goto(url);
let harvest = await collectSearchHarvest(page, limit, requestedFilters);
// after: retry the harvest once before surfacing the timeout
let harvest;
try {
harvest = await collectSearchHarvest(page, limit, requestedFilters);
} catch (err) {
if (err instanceof TimeoutError) {
harvest = await collectSearchHarvest(page, limit, requestedFilters);
} else { throw err; }
} Defensive patterns
Strategy: retry
Validate before calling
// Probe reachability before invoking
const res = await fetch('https://www.xiaohongshu.com/search_result?keyword=test', { method: 'HEAD' });
if (res.status === 403 || res.status === 429) throw new Error('Site is throttling; back off before searching'); Type guard
function isTimeout(err) { return err instanceof TimeoutError || err?.name === 'TimeoutError'; } Try / catch
try {
rows = await cli('xiaohongshu search', query);
} catch (err) {
if (isTimeout(err)) {
await sleep(BACKOFF_MS); // let slow render / throttle pass
rows = await cli('xiaohongshu search', query); // retry once
} else { throw err; }
} Prevention
- Retry once with backoff before giving up; timeouts here are often transient render slowness.
- Avoid running searches through slow proxies or heavy VPN tunnels.
- Keep the browser session authenticated so login-wall interstitials don't stall rendering.
- Watch for repeated timeouts from the same query — it may indicate a DOM redesign requiring a CLI update.
When it happens
Trigger: page.evaluate(WAIT_FOR_CONTENT_JS) in collectSearchHarvest (clis/xiaohongshu/search.js:787) returns the sentinel 'timeout' — i.e. no search-result cards, login wall, or security banner appeared within the fixed wait window after page.goto(url). Any slow network, heavy anti-bot interstitial, or an unexpected DOM layout triggers it.
Common situations: Slow or proxied network connections where lazy-loaded results exceed CONTENT_WAIT_SECONDS; Xiaohongshu showing an A/B-tested or redesigned layout the wait script does not recognize; heavy anti-bot challenge pages; very obscure queries rendering a near-empty feed the detector misses.
Related errors
- Ctrip round-trip flight page did not render flight cards (st
- weixin search failed while loading Sogou results
- No feed items in the hydrated store.
- Editing form did not appear after image acquisition. The pag
- ${verb} could not be verified: no success marker or post-sub
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/62f7d7a21d5d9e75.
Report an issue: GitHub.