jackwener/OpenCLI · error · CommandExecutionError
Xiaohongshu search masonry remained collapsed after one fres
Error message
Xiaohongshu search masonry remained collapsed after one fresh-tab recovery.
What it means
Thrown when a Xiaohongshu search returned a collapsed masonry render, the library already attempted its one built-in recovery (replacing the tab with a fresh one and re-collecting), and the results were still collapsed. It means the site served a degraded/anti-bot or not-logged-in render even after recovery, so no usable masonry could be obtained.
Source
Thrown at clis/xiaohongshu/search.js:895
{ name: 'note-type', type: 'string', default: 'all', choices: ['all', 'video', 'image'], help: 'Note type' },
{ name: 'publish-time', type: 'string', default: 'anytime', choices: ['anytime', 'day', 'week', 'half-year'], help: 'Publish time range' },
{ name: 'scope', type: 'string', default: 'all', choices: ['all', 'seen', 'unseen', 'following'], help: 'Search scope' },
{ name: 'location', type: 'string', default: 'all', choices: ['all', 'same-city', 'nearby'], help: 'Location distance' },
],
columns: ['rank', 'title', 'author', 'likes', 'published_at', 'url'],
func: async (page, kwargs) => {
try {
const limit = parseLimit(kwargs.limit);
const requestedFilters = resolveSearchFilters(kwargs);
const keyword = encodeURIComponent(kwargs.query);
const url = `https://www.xiaohongshu.com/search_result?keyword=${keyword}&source=web_search_result_notes`;
await page.goto(url);
let harvest = await collectSearchHarvest(page, limit, requestedFilters);
if (isCollapsedRender(harvest.diag)) {
await replaceCollapsedTab(page, url);
harvest = await collectSearchHarvest(page, limit, requestedFilters);
if (isCollapsedRender(harvest.diag)) {
throw new CommandExecutionError(
'Xiaohongshu search masonry remained collapsed after one fresh-tab recovery.',
'Retry later or use a different logged-in browser session.',
);
}
}
const rows = harvest.rows
.filter((item) => item.title)
.slice(0, limit);
if (rows.length === 0) {
throw new EmptyResultError('xiaohongshu search', 'No usable notes were rendered for this query.');
}
return rows
.map((item, i) => ({
rank: i + 1,
...item,
published_at: noteIdToDate(item.url),
}));
}View on GitHub (pinned to 49907e53dc)
Solutions
- Wait and retry later — the collapsed render is usually a temporary rate-limit/risk-control response.
- Log in again or point the CLI at a different logged-in browser session (as the hint says).
- Reduce query frequency / add delays between searches to avoid triggering risk control.
- Verify the browser profile actually has an active xiaohongshu.com login by opening the site manually.
- Update the library in case Xiaohongshu changed the collapsed-render markup that isCollapsedRender detects.
Example fix
// before
await runSearch(query); // throws on collapsed render
// after
await sleep(backoffMs);
try {
await runSearch(query);
} catch (e) {
if (String(e).includes('remained collapsed')) await switchToFreshSessionAndRetry(query);
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// before searching, confirm the session can render a known page's masonry
const probe = await collectSearchHarvest(probePage, 1, {});
if (isCollapsedRender(probe.diag)) throw new Error('session currently serving collapsed renders; wait before searching'); Try / catch
try {
await xhsSearch(query);
} catch (err) {
if (String(err.message).includes('remained collapsed')) {
await sleep(60_000);
return retryWithFreshSession(query);
}
throw err;
} Prevention
- Throttle search frequency to avoid XHS risk control
- Use a healthy logged-in browser session
- Back off and retry later rather than hammering
- Verify login state manually before batch runs
When it happens
Trigger: collectSearchHarvest() returns diag where isCollapsedRender(harvest.diag) is true, replaceCollapsedTab(page, url) succeeds, the harvest is re-run, and isCollapsedRender(harvest.diag) is still true.
Common situations: Xiaohongshu rate-limiting or risk control serving the collapsed view to the session; expired login cookies in the browser profile; scraping too frequently from the same session; site-side A/B changes to the collapsed page.
Related errors
- IMDb blocked this request
- IMDb blocked this request
- IMDb blocked this request
- IMDb blocked this request
- [taxonomy=selector_drift] site=jianyu command=search blocked
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ed35a9929c3ae9cf.
Report an issue: GitHub.