jackwener/OpenCLI · error · CommandExecutionError
Browser session required for linkedin salesnav-message
Error message
Browser session required for linkedin salesnav-message
What it means
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.
Source
Thrown at clis/linkedin/salesnav-message.js:267
cli({
site: 'linkedin',
name: 'salesnav-message',
access: 'write',
description: 'Send or dry-run a LinkedIn Sales Navigator InMail to a lead using the Sales Navigator messaging API',
domain: LINKEDIN_DOMAIN,
strategy: Strategy.UI,
browser: true,
args: [
{ name: 'recipient', type: 'string', required: true, positional: true, help: 'Sales Navigator lead URL, LinkedIn /in/ URL from salesnav-search, or urn:li:fs_salesProfile:(...)' },
{ name: 'subject', type: 'string', required: true, help: 'InMail subject' },
{ name: 'body', type: 'string', required: true, help: 'InMail body' },
{ name: 'send', type: 'bool', default: false, help: 'Actually send the InMail. Default is dry-run validation only.' },
{ name: 'copy-to-crm', type: 'bool', default: false, help: 'Set Sales Navigator copyToCrm on the message request' },
],
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'],
func: async (page, args) => {
if (!page) throw new CommandExecutionError('Browser session required for linkedin salesnav-message');
const recipientArg = requireStringArg(args, 'recipient', '--recipient');
const subject = requireStringArg(args, 'subject', '--subject');
const body = String(args.body ?? '').trim();
if (!body) throw new ArgumentError('--body is required');
await page.goto(SALES_HOME);
await page.wait(4);
const csrf = await getCsrf(page);
const recipient = await resolveRecipient(page, parseRecipient(recipientArg), csrf);
let summary = { recipient: '', title: '', company: '', degree: '', inmail_restriction: '', open_link: false };
const profileUrl = profileApiUrl(recipient);
if (profileUrl) {
const profileResult = requireFetchResult(unwrapEvaluateResult(await page.evaluate(fetchJsonScript(profileUrl, csrf))), 'LinkedIn Sales Navigator profile API');
summary = requireProfileSummary(profileResult.json);
}
if (summary.inmail_restriction && summary.inmail_restriction !== 'NO_RESTRICTION') {
throw new CommandExecutionError('Sales Navigator InMail blocked by recipient restriction', summary.inmail_restriction);View on GitHub (pinned to 49907e53dc)
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
Example fix
// before
await registry.run('linkedin', 'salesnav-message', null, args);
// after
const page = await browser.newPage();
await registry.run('linkedin', 'salesnav-message', page, args); Defensive patterns
Strategy: validation
Validate before calling
if (!page) throw new Error('salesnav-message needs a browser page — launch the browser session first'); Type guard
const hasBrowserPage = (page) => page != null && typeof page.goto === 'function' && typeof page.evaluate === 'function';
Try / catch
try {
await cli.run('linkedin', 'salesnav-message', page, args);
} catch (err) {
if (/Browser session required/.test(err.message)) {
console.error('Start the browser (e.g. `opencli browser start`) and retry');
} else throw err;
} Prevention
- 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
When it happens
Trigger: Calling the registered 'linkedin salesnav-message' command without an attached/launched browser, or from a non-browser execution mode where func receives page=null.
Common situations: 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.
Related errors
- Sales Navigator messaging threads API returned malformed pay
- Sales Navigator messaging threads API returned malformed thr
- Sales Navigator messaging thread row missing id
- ${label} authentication failed (HTTP ${result.status || 'aut
- ${label} returned an unexpected response
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c98504e6e7bfa889.
Report an issue: GitHub.