{"record":{"id":"0b3aef0e2dd97a97","repo":"jackwener/OpenCLI","slug":"failed-to-replace-collapsed-xiaohongshu-search-tab","errorCode":null,"errorMessage":"Failed to replace collapsed Xiaohongshu search tab: ${error?.message ?? String(error)}.${cleanupContext}","messagePattern":"Failed to replace collapsed Xiaohongshu search tab: (.+?)\\.(.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/search.js","lineNumber":859,"sourceCode":"            }\n            if (restoredPrevious) {\n                try {\n                    await page.closeTab(freshPage);\n                }\n                catch (cleanupError) {\n                    cleanupErrors.push(cleanupError?.message ?? String(cleanupError));\n                }\n            }\n            else {\n                // If the old target disappeared despite the original error,\n                // keep the fresh preferred target bound for --keep-tab.\n                page.setActivePage(freshPage);\n            }\n        }\n        const cleanupContext = cleanupErrors.length > 0\n            ? ` Cleanup also failed: ${cleanupErrors.join('; ')}.`\n            : '';\n        throw new CommandExecutionError(\n            `Failed to replace collapsed Xiaohongshu search tab: ${error?.message ?? String(error)}.${cleanupContext}`,\n        );\n    }\n}\n\nexport const command = cli({\n    site: 'xiaohongshu',\n    name: 'search',\n    access: 'read',\n    description: '搜索小红书笔记',\n    domain: 'www.xiaohongshu.com',\n    strategy: Strategy.COOKIE,\n    navigateBefore: false,\n    args: [\n        { name: 'query', required: true, positional: true, help: 'Search keyword' },\n        { name: 'limit', type: 'int', default: 20, help: 'Number of results' },\n        { name: 'sort', type: 'string', default: 'comprehensive', choices: ['comprehensive', 'latest', 'most-liked', 'most-commented', 'most-collected'], help: 'Sort order' },\n        { name: 'note-type', type: 'string', default: 'all', choices: ['all', 'video', 'image'], help: 'Note type' },","sourceCodeStart":841,"sourceCodeEnd":877,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/search.js#L841-L877","documentation":"This error is thrown by replaceCollapsedTab() when it fails to swap a collapsed Xiaohongshu search results tab for a fresh one. The browser-side navigation/replacement step raised an error, and the message embeds the original error message plus any cleanup failures that occurred while closing the collapsed tab. It signals that the automated fresh-tab recovery path itself broke, not just that results were collapsed.","triggerScenarios":"collectSearchHarvest() detects a collapsed masonry render (isCollapsedRender), replaceCollapsedTab is invoked to open a new tab and re-goto the search URL, and either the new-page creation, page.goto, or page.setActivePage throws; the catch block then attempts to close the broken pages and throws CommandExecutionError with cleanupErrors appended.","commonSituations":"The logged-in browser session was closed or the connection to the browser dropped mid-run; a popup blocker or browser profile prevents opening a new tab; the page object was invalidated by navigation; cleanup (closing old tabs) fails because the target was already closed.","solutions":["Check that the browser session backing the page is still alive and the logged-in profile is valid, then retry the search command.","Inspect the embedded `${error.message}` in the message for the underlying browser error and fix that root cause (e.g. navigation timeout, context destroyed).","If cleanup also failed ('Cleanup also failed' suffix), manually close stale tabs/pages before rerunning.","Retry later or with a different logged-in browser session as the recovery path suggests; add your own retry wrapper around the CLI call.","Upgrade/verify the browser automation runtime (chromium/CDP) version matches what the library expects."],"exampleFix":"// before\nawait replaceCollapsedTab(page, url);\n// after\ntry {\n  await replaceCollapsedTab(page, url);\n} catch (e) {\n  if (!browser.isConnected()) await reopenBrowserAndLogin();\n  await replaceCollapsedTab(page, url);\n}","handlingStrategy":"try-catch","validationCode":"if (!browser.isConnected()) throw new Error('browser session closed before search');","typeGuard":"function isSessionAlive(browser) { return !!browser && typeof browser.isConnected === 'function' && browser.isConnected(); }","tryCatchPattern":"try {\n  await xhsSearch(query, { limit });\n} catch (err) {\n  if (String(err.message).includes('Failed to replace collapsed')) {\n    await restartBrowserSession();\n    return xhsSearch(query, { limit });\n  }\n  throw err;\n}","preventionTips":["Keep the browser session alive and logged in for the whole command run","Avoid closing tabs or the browser concurrently with a running search","Retry with a fresh logged-in session when recovery fails","Monitor the embedded underlying error message for root cause"],"tags":["browser-automation","xhs","tab-recovery","command-execution"],"backgroundTag":"browser-session-invalidated","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}