{"record":{"id":"480daf7f87c3a20e","repo":"jackwener/OpenCLI","slug":"unexpected-xiaohongshu-search-wait-payload-shape","errorCode":null,"errorMessage":"Unexpected Xiaohongshu search wait payload shape.","messagePattern":"Unexpected Xiaohongshu search wait payload shape\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/search.js","lineNumber":798,"sourceCode":"          },\n        };\n      })()\n    `;\n}\n\nasync function collectSearchHarvest(page, limit, requestedFilters) {\n    const waitResult = unwrapEvaluateResult(await page.evaluate(WAIT_FOR_CONTENT_JS));\n    if (waitResult === 'login_wall') {\n        throw new AuthRequiredError('www.xiaohongshu.com', 'Xiaohongshu search results are blocked behind a login wall');\n    }\n    if (waitResult === 'security_block') {\n        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.');\n    }\n    if (waitResult === 'timeout') {\n        throw new TimeoutError('xiaohongshu search content', CONTENT_WAIT_SECONDS);\n    }\n    if (waitResult !== 'content') {\n        throw new CommandExecutionError('Unexpected Xiaohongshu search wait payload shape.');\n    }\n    requireFilterApplication(await page.evaluate(buildApplySearchFiltersJs(requestedFilters)));\n    const harvestOptions = harvestOptionsForLimit(limit);\n    const harvest = requireHarvestPayload(await page.evaluate(buildScrollHarvestJs('www.xiaohongshu.com', limit, harvestOptions)), 'www.xiaohongshu.com');\n    if (harvest.diag.securityBlock) {\n        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.');\n    }\n    return harvest;\n}\n\nasync function replaceCollapsedTab(page, url) {\n    if (typeof page.getActivePage !== 'function' || typeof page.newTab !== 'function' ||\n        typeof page.setActivePage !== 'function' || typeof page.selectTab !== 'function' ||\n        typeof page.closeTab !== 'function') {\n        throw new CommandExecutionError(\n            'Xiaohongshu search rendered in a collapsed tab, but this browser session cannot replace the failed target.',\n            'Retry the command in a Browser Bridge session that supports tab replacement.',\n        );","sourceCodeStart":780,"sourceCodeEnd":816,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/search.js#L780-L816","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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')."],"exampleFix":"// before (modified wait script)\nreturn { status: 'ok', state: 'content' };\n// after (restore sentinel contract)\nreturn 'content';","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function isWaitPayloadShapeError(err) {\n  return err?.name === 'CommandExecutionError' &&\n    typeof err?.message === 'string' &&\n    err.message.includes('Unexpected Xiaohongshu search wait payload shape');\n}","tryCatchPattern":"try {\n  rows = await cli('xiaohongshu search', query);\n} catch (err) {\n  if (isWaitPayloadShapeError(err)) {\n    // internal contract break: retry once, then escalate/report rather than loop\n    rows = await cli('xiaohongshu search', query);\n  } else { throw err; }\n}","preventionTips":["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."],"tags":["internal-contract","browser-automation","payload-shape","xiaohongshu"],"backgroundTag":"unexpected-payload-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}