jackwener/OpenCLI · error · CommandExecutionError
Unexpected Xiaohongshu search wait payload shape.
Error message
Unexpected Xiaohongshu search wait payload shape.
What it means
collectSearchHarvest expects the browser-side wait script to resolve to one of four known sentinels: 'login_wall', 'security_block', 'timeout', or 'content'. If the browser returns anything else — including null, undefined, or an object — the command throws this CommandExecutionError because it cannot classify the page state. This is a defensive contract check signaling the in-page instrumentation returned an unexpected shape.
Source
Thrown at clis/xiaohongshu/search.js:798
},
};
})()
`;
}
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(
'Xiaohongshu search rendered in a collapsed tab, but this browser session cannot replace the failed target.',
'Retry the command in a Browser Bridge session that supports tab replacement.',
);View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command — a transient navigation failure can make evaluate resolve to undefined.
- Check whether the browser session/driver was modified or wrapped in a way that changes page.evaluate return values (e.g. result unwrapping).
- Inspect the actual waitResult: add temporary logging around page.evaluate(WAIT_FOR_CONTENT_JS) at clis/xiaohongshu/search.js:787.
- If you patched WAIT_FOR_CONTENT_JS, restore its documented return contract ('content' | 'login_wall' | 'security_block' | 'timeout').
Example fix
// before (modified wait script)
return { status: 'ok', state: 'content' };
// after (restore sentinel contract)
return 'content'; Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
function isWaitPayloadShapeError(err) {
return err?.name === 'CommandExecutionError' &&
typeof err?.message === 'string' &&
err.message.includes('Unexpected Xiaohongshu search wait payload shape');
} Try / catch
try {
rows = await cli('xiaohongshu search', query);
} catch (err) {
if (isWaitPayloadShapeError(err)) {
// internal contract break: retry once, then escalate/report rather than loop
rows = await cli('xiaohongshu search', query);
} else { throw err; }
} Prevention
- Do not modify WAIT_FOR_CONTENT_JS or wrap page.evaluate without preserving sentinel return values.
- Use an unmodified, version-matched browser driver/session with the CLI.
- Retry once — a single occurrence is usually transient navigation noise; repeated occurrences indicate a code/DOM contract change.
When it happens
Trigger: waitResult !== 'content' after the login_wall/security_block/timeout checks, i.e. page.evaluate(WAIT_FOR_CONTENT_JS) returned an unrecognized value — typically null/undefined from an evaluate serialization failure, or a modified WAIT_FOR_CONTENT_JS payload shape.
Common situations: Running a modified/monkey-patched WAIT_FOR_CONTENT_JS or an incompatible browser driver that fails evaluate silently; the page navigating away mid-wait so evaluate resolves to undefined; a locally edited checkout where the wait script's return contract was changed without updating this dispatcher.
Related errors
- Douyin search: unexpected evaluator payload shape
- ${label} returned a malformed payload
- ${label} returned malformed rows
- Unexpected Rednote search extraction payload shape; expected
- Twitter lists returned an unexpected payload shape
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/480daf7f87c3a20e.
Report an issue: GitHub.