{"record":{"id":"2b3b9b51c30e405e","repo":"jackwener/OpenCLI","slug":"browser-page-required-2b3b9b","errorCode":null,"errorMessage":"Browser page required","messagePattern":"Browser page required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/publish.js","lineNumber":1182,"sourceCode":"    access: 'write',\n    description: '小红书发布图文笔记 (creator center UI automation)',\n    domain: 'creator.xiaohongshu.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    navigateBefore: false,\n    args: [\n        { name: 'content', required: true, positional: true, help: '笔记正文' },\n        { name: 'title', required: true, help: '笔记标题 (最多20字)' },\n        { name: 'images', required: false, help: '图片路径，逗号分隔，最多9张 (jpg/png/gif/webp)' },\n        { name: 'card-text', required: false, help: `文字配图卡片文字，多张卡片用 ${CARD_TEXT_DELIM} 分隔，卡内换行用 \\\\n` },\n        { name: 'card-style', required: false, help: `文字配图卡片样式，运行时按页面实际选项匹配；找不到会失败。省略时使用${DEFAULT_CARD_STYLE}。可选: ${CARD_STYLE_GUIDE.map(([n, s]) => `${n}(${s})`).join(' ')}` },\n        { name: 'topics', required: false, help: '话题标签，逗号分隔，不含 # 号' },\n        { name: 'draft', type: 'bool', default: false, help: '保存为草稿，不直接发布' },\n    ],\n    columns: ['status', 'detail'],\n    func: async (page, kwargs) => {\n        if (!page)\n            throw new Error('Browser page required');\n        const title = String(kwargs.title ?? '').trim();\n        const content = String(kwargs.content ?? '').trim();\n        const imagePaths = kwargs.images\n            ? String(kwargs.images).split(',').map((s) => s.trim()).filter(Boolean)\n            : [];\n        const topics = kwargs.topics\n            ? String(kwargs.topics).split(',').map((s) => s.trim()).filter(Boolean)\n            : [];\n        const isDraft = Boolean(kwargs.draft);\n        const cardText = kwargs['card-text'] ? String(kwargs['card-text']) : '';\n        const cards = cardText\n            ? cardText.split(CARD_TEXT_DELIM).map((s) => s.trim()).filter(Boolean)\n            : [];\n        const cardStyle = kwargs['card-style'] ? String(kwargs['card-style']).trim() : '';\n        const isTextImage = cards.length > 0;\n        // ── Validate inputs ────────────────────────────────────────────────────────\n        if (!title)\n            throw new ArgumentError('--title is required');","sourceCodeStart":1164,"sourceCodeEnd":1200,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/publish.js#L1164-L1200","documentation":"The xhs publish command's func is invoked with a browser `page` handle supplied by the CLI runner; if the runner could not provide an active browser page the handler throws this plain Error immediately. It is a defensive guard ensuring all subsequent automation (page.goto, page.wait, clicks) has a real page to operate on.","triggerScenarios":"Invoking the xiaohongshu publish command without an active browser session — e.g. the browser failed to launch, was closed beforehand, or the command was called programmatically passing null/undefined as the page argument.","commonSituations":"Browser not started before running the command (missing --browser/login step); headless browser crashed or was closed mid-session; calling the exported command function directly in tests without stubbing a page; browser startup failure swallowed upstream.","solutions":["Launch/login to the browser first (run the xhs login/open command) before publishing","Check that the browser process is alive and not crashed; restart it","If calling the command programmatically, pass a valid playwright/puppeteer Page object","Check earlier logs for browser-launch errors that left page undefined"],"exampleFix":"// before\nawait publishCommand.func(null, { title: 'hi', content: 'body' });\n// after\nconst page = await openBrowser();\nawait publishCommand.func(page, { title: 'hi', content: 'body' });","handlingStrategy":"validation","validationCode":"if (!page || typeof page.goto !== 'function') {\n  throw new Error('Launch the browser session before running the xhs publish command');\n}","typeGuard":"function hasPage(p) {\n  return !!p && typeof p.goto === 'function' && typeof p.wait === 'function';\n}","tryCatchPattern":"try {\n  await runPublish(args);\n} catch (e) {\n  if (e.message === 'Browser page required') {\n    await launchAndLogin();\n    await runPublish(args);\n  } else throw e;\n}","preventionTips":["Always run the browser open/login command before publish","Check browser process health in long-running scripts","When calling func() directly, stub or pass a real Page object"],"tags":["guard-clause","browser","xiaohongshu","missing-argument"],"backgroundTag":"missing-browser-context","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}