{"record":{"id":"3eb6a01c70b45c4f","repo":"jackwener/OpenCLI","slug":"browser-session-required-for-xiaohongshu-unfollow","errorCode":null,"errorMessage":"Browser session required for xiaohongshu unfollow","messagePattern":"Browser session required for xiaohongshu unfollow","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/unfollow.js","lineNumber":201,"sourceCode":"    name: 'unfollow',\n    access: 'write',\n    description: '取消关注小红书用户 (profile UI automation)',\n    domain: 'www.xiaohongshu.com',\n    strategy: Strategy.COOKIE,\n    navigateBefore: false,\n    browser: true,\n    args: [\n        {\n            name: 'user-id',\n            required: true,\n            positional: true,\n            help: 'User ID (e.g. 5d8f88dc0000000001005d3a) or profile URL',\n        },\n    ],\n    columns: ['status', 'user_id', 'url'],\n    func: async (page, kwargs) => {\n        if (!page) {\n            throw new CommandExecutionError('Browser session required for xiaohongshu unfollow');\n        }\n        try {\n            const userId = assertUserId(kwargs['user-id']);\n            const url = `https://www.xiaohongshu.com/user/profile/${userId}`;\n            await page.goto(url);\n            await page.wait({ time: PROFILE_SETTLE_MS / 1000 });\n\n            const hrefRaw = unwrapEvaluateResult(await page.evaluate('() => location.href'));\n            if (typeof hrefRaw !== 'string') {\n                throw new CommandExecutionError('xiaohongshu/unfollow: malformed current-url payload');\n            }\n            const parsedHref = new URL(hrefRaw);\n            if (parsedHref.protocol !== 'https:' || !isXiaohongshuHost(parsedHref.hostname)) {\n                throw new CommandExecutionError(\n                    `xiaohongshu/unfollow: expected Xiaohongshu profile host, got ${parsedHref.hostname}`,\n                );\n            }\n            if (/\\/login(?:[/?#]|$)/i.test(parsedHref.pathname)) {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/unfollow.js#L183-L219","documentation":"The xiaohongshu/unfollow command is a browser-automation command (browser: true) that drives a Chrome page to click the unfollow button. The cli func receives `page` from the runtime; when there is no browser session (page is null/undefined), this CommandExecutionError is thrown before any work happens. It signals that the command cannot run headless-of-browser.","triggerScenarios":"Invoking the command without a connected/started browser session; running in an environment where Chrome is not available or the session failed to launch; calling the underlying func directly (e.g. in tests or programmatic use) with page=null; the browser process crashed or was closed before the command ran.","commonSituations":"Forgetting to start the browser/login flow before running site commands; CI containers without Chrome; stale session after Chrome was manually closed; a wrapper library that passes null page when Strategy.COOKIE session setup fails silently.","solutions":["Start/ensure the browser session before running the command (launch Chrome and log into www.xiaohongshu.com as the library requires)","Re-run the command so the CLI runtime can attach a fresh page; if the previous session crashed, restart it","If calling func programmatically, pass a real page object from your browser/session helper instead of null","Verify Chrome is installed and reachable in your environment (CI: use a Chrome-capable image)"],"exampleFix":"// before\nawait unfollowFunc(null, { 'user-id': id });  // page is null\n// after\nconst page = await session.openPage('www.xiaohongshu.com');\nawait unfollowFunc(page, { 'user-id': id });","handlingStrategy":"validation","validationCode":"if (!page) throw new Error('Open a browser session before calling xiaohongshu unfollow');","typeGuard":"function hasPage(p) { return !!p && typeof p.goto === 'function' && typeof p.evaluate === 'function'; }","tryCatchPattern":"try { await cli.unfollow({ 'user-id': id }); } catch (e) { if (String(e.message).includes('Browser session required')) { await session.start(); /* then retry */ } else throw e; }","preventionTips":["Always start the browser session and log into xiaohongshu.com before site commands","Check for a live page object in wrapper code before invoking func","In CI, use a Chrome-capable image and verify the session launched","Handle session-crash events by restarting the browser before the next command"],"tags":["browser","session","precondition"],"backgroundTag":"browser-session-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}