{"record":{"id":"c98504e6e7bfa889","repo":"jackwener/OpenCLI","slug":"browser-session-required-for-linkedin-salesnav-mes","errorCode":null,"errorMessage":"Browser session required for linkedin salesnav-message","messagePattern":"Browser session required for linkedin salesnav-message","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/salesnav-message.js","lineNumber":267,"sourceCode":"\ncli({\n  site: 'linkedin',\n  name: 'salesnav-message',\n  access: 'write',\n  description: 'Send or dry-run a LinkedIn Sales Navigator InMail to a lead using the Sales Navigator messaging API',\n  domain: LINKEDIN_DOMAIN,\n  strategy: Strategy.UI,\n  browser: true,\n  args: [\n    { name: 'recipient', type: 'string', required: true, positional: true, help: 'Sales Navigator lead URL, LinkedIn /in/ URL from salesnav-search, or urn:li:fs_salesProfile:(...)' },\n    { name: 'subject', type: 'string', required: true, help: 'InMail subject' },\n    { name: 'body', type: 'string', required: true, help: 'InMail body' },\n    { name: 'send', type: 'bool', default: false, help: 'Actually send the InMail. Default is dry-run validation only.' },\n    { name: 'copy-to-crm', type: 'bool', default: false, help: 'Set Sales Navigator copyToCrm on the message request' },\n  ],\n  columns: ['status', 'recipient', 'title', 'company', 'credits_remaining', 'credits_before', 'credits_after', 'sent_in_salesnav', 'message_chars', 'subject_chars', 'recipient_urn', 'degree', 'inmail_restriction', 'open_link'],\n  func: async (page, args) => {\n    if (!page) throw new CommandExecutionError('Browser session required for linkedin salesnav-message');\n    const recipientArg = requireStringArg(args, 'recipient', '--recipient');\n    const subject = requireStringArg(args, 'subject', '--subject');\n    const body = String(args.body ?? '').trim();\n    if (!body) throw new ArgumentError('--body is required');\n\n    await page.goto(SALES_HOME);\n    await page.wait(4);\n    const csrf = await getCsrf(page);\n    const recipient = await resolveRecipient(page, parseRecipient(recipientArg), csrf);\n\n    let summary = { recipient: '', title: '', company: '', degree: '', inmail_restriction: '', open_link: false };\n    const profileUrl = profileApiUrl(recipient);\n    if (profileUrl) {\n      const profileResult = requireFetchResult(unwrapEvaluateResult(await page.evaluate(fetchJsonScript(profileUrl, csrf))), 'LinkedIn Sales Navigator profile API');\n      summary = requireProfileSummary(profileResult.json);\n    }\n    if (summary.inmail_restriction && summary.inmail_restriction !== 'NO_RESTRICTION') {\n      throw new CommandExecutionError('Sales Navigator InMail blocked by recipient restriction', summary.inmail_restriction);","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-message.js#L249-L285","documentation":"The salesnav-message CLI command requires a live browser page (it navigates Sales Navigator and reads cookies). The command function throws CommandExecutionError immediately if page is falsy — i.e. the command was invoked outside a browser session context.","triggerScenarios":"Calling the registered 'linkedin salesnav-message' command without an attached/launched browser, or from a non-browser execution mode where func receives page=null.","commonSituations":"Running the CLI in headless-API mode without launching the browser; forgetting the browser launch/start step; wiring the command into a batch runner that doesn't provision pages.","solutions":["Launch/attach a browser session before running the command","Use the CLI's normal browser-backed invocation path","Verify your runner passes the page argument to the command func","Check for browser launch failures earlier in the logs"],"exampleFix":"// before\nawait registry.run('linkedin', 'salesnav-message', null, args);\n// after\nconst page = await browser.newPage();\nawait registry.run('linkedin', 'salesnav-message', page, args);","handlingStrategy":"validation","validationCode":"if (!page) throw new Error('salesnav-message needs a browser page — launch the browser session first');","typeGuard":"const hasBrowserPage = (page) => page != null && typeof page.goto === 'function' && typeof page.evaluate === 'function';","tryCatchPattern":"try {\n  await cli.run('linkedin', 'salesnav-message', page, args);\n} catch (err) {\n  if (/Browser session required/.test(err.message)) {\n    console.error('Start the browser (e.g. `opencli browser start`) and retry');\n  } else throw err;\n}","preventionTips":["Always launch/attach the browser before browser-backed commands","Assert page != null in your runner before invoking commands","Don't mix API-only and browser-backed command modes","Check browser launch logs for earlier failures"],"tags":["browser","linkedin","sales-navigator","missing-session"],"backgroundTag":"browser-session-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}