{"record":{"id":"08ad16e3238966b5","repo":"jackwener/OpenCLI","slug":"browser-session-required-for-linkedin-salesnav-thr","errorCode":null,"errorMessage":"Browser session required for linkedin salesnav-thread","messagePattern":"Browser session required for linkedin salesnav-thread","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-thread.js","lineNumber":185,"sourceCode":"  return thread;\n}\n\ncli({\n  site: 'linkedin',\n  name: 'salesnav-thread',\n  access: 'read',\n  description: 'Return full Sales Navigator message history for a thread id, Sales Navigator inbox URL, lead URL, recipient urn, or exact recipient name',\n  domain: LINKEDIN_DOMAIN,\n  strategy: Strategy.UI,\n  browser: true,\n  args: [\n    { name: 'thread-or-recipient', type: 'string', required: true, positional: true, help: 'Sales Navigator inbox URL/thread id, Sales Navigator lead URL, recipient urn, or exact participant name' },\n    { name: 'limit', type: 'number', default: DEFAULT_MESSAGE_LIMIT, help: 'Maximum messages to return (1-500)' },\n    { name: 'max-pages', type: 'number', default: 30, help: 'Maximum inbox pages to scan when resolving a recipient' },\n  ],\n  columns: ['index', 'thread_id', 'thread_url', 'sender', 'text', 'timestamp', 'subject', 'message_id', 'sender_urn', 'delivered_at', 'type', 'total_message_count'],\n  func: async (page, args) => {\n    if (!page) throw new CommandExecutionError('Browser session required for linkedin salesnav-thread');\n    const input = normalizeWhitespace(args['thread-or-recipient']);\n    if (!input) throw new ArgumentError('thread-or-recipient is required');\n    const limit = parseLimit(args.limit, DEFAULT_MESSAGE_LIMIT);\n    const maxPages = parseLimit(args['max-pages'], 30);\n    await page.goto(SALES_INBOX_URL);\n    await page.wait(4);\n    const threadId = await resolveThreadId(page, input, { maxPages });\n    const csrf = await getCsrf(page);\n    const thread = await fetchThreadWithPagination(page, csrf, threadId, limit);\n    const messages = parseSalesnavThreadMessages(thread).slice(0, limit);\n    if (messages.length === 0) throw new EmptyResultError('linkedin salesnav-thread', `No messages found for ${threadId}`);\n    return messages.map((message) => ({\n      ...message,\n      thread_url: salesnavThreadUrl(threadId),\n      total_message_count: Number(thread?.totalMessageCount || messages.length),\n    }));\n  },\n});","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-thread.js#L167-L203","documentation":"The linkedin salesnav-thread command's func requires a live Puppeteer-style Page; if the page argument is falsy it throws CommandExecutionError('Browser session required for ...'). All resolution (inbox scraping, CSRF extraction, API calls via page.evaluate) depends on an authenticated browser context, so the command cannot run headless-without-browser.","triggerScenarios":"Invoking the linkedin salesnav-thread CLI without starting/attaching a browser session, so the CLI harness passes page = null/undefined into func.","commonSituations":"Running the command in an environment where the browser flag/wrapper was omitted; a browser launch failure silently yielding no page; calling func directly in tests without a fixture page; CI containers lacking Chrome.","solutions":["Start the CLI/browser harness so a logged-in LinkedIn session page is available before running the command (e.g. the site's standard 'open/login' flow).","Verify the browser launched successfully and the page handle is passed through to the command dispatcher.","In tests, pass a stub page object or mark the test as requiring a browser session.","Check CI images include a working Chrome/Chromium and non-headless-safe flags if applicable."],"exampleFix":"// before\nawait cli.run(['linkedin','salesnav-thread', threadId])            // no browser session\n// after\nawait browserSession.login('linkedin')                             // establish signed-in page\nawait cli.run(['linkedin','salesnav-thread', threadId], { page })","handlingStrategy":"validation","validationCode":"if (!page) throw new Error('launch/login to a browser session before running linkedin salesnav-thread');","typeGuard":"function isPage(p){ return !!p && typeof p.goto === 'function' && typeof p.evaluate === 'function'; }","tryCatchPattern":"try { await run() } catch (e) { if (/Browser session required/.test(e.message)) { await startBrowserAndLogin(); await run(); } else throw e; }","preventionTips":["Always establish (and verify) the browser/login session before LinkedIn commands.","In tests, inject a stub page or skip browser-requiring tests.","Ensure CI images ship Chrome and correct launch flags.","Fail the pipeline early if the browser harness reports no page handle."],"tags":["browser-session","prerequisite","linkedin","command-execution"],"backgroundTag":"browser-session-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}