jackwener/OpenCLI · critical · AuthRequiredError

LinkedIn Sales Navigator API auth failed (HTTP ' + (result.s

Error message

LinkedIn Sales Navigator API auth failed (HTTP ' + (result.status || '') + '). Confirm the account has Sales Navigator access.

What it means

requireLeadSearchResult inspects the in-page fetch result and throws AuthRequiredError when result.authRequired is true, i.e. the salesApiLeadSearch endpoint answered 401 or 403 (see fetchLeadSearchScript line 53). This means the browser session is not authenticated to Sales Navigator or lacks the Sales Navigator entitlement, so the search cannot proceed.

Source

Thrown at clis/linkedin/salesnav-search.js:112

      throw new CommandExecutionError('Sales Navigator lead row missing profile identity');
    }
    leads.push({
      name,
      title: normalizeWhitespace(pos.title || ''),
      company: normalizeWhitespace(pos.companyName || ''),
      location: normalizeWhitespace(el.geoRegion || ''),
      degree: normalizeWhitespace(el.degree || ''),
      profile_url: profileUrlFromEntityUrn(entityUrn),
      lead_url: leadUrlFromEntityUrn(entityUrn),
      recipient_urn: entityUrn,
    });
  }
  return leads;
}

function requireLeadSearchResult(result) {
  if (result?.authRequired) {
    throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn Sales Navigator API auth failed (HTTP ' + (result.status || '') + '). Confirm the account has Sales Navigator access.');
  }
  if (result?.error) {
    throw new CommandExecutionError('Sales Navigator lead search API returned an unexpected response', result.error);
  }
  if (!result || !result.json) {
    throw new CommandExecutionError('Sales Navigator lead search API returned an unexpected response', 'no_json');
  }
  return result.json;
}

cli({
  site: 'linkedin',
  name: 'salesnav-search',
  access: 'read',
  description: 'Search LinkedIn Sales Navigator for people leads by keyword',
  domain: LINKEDIN_DOMAIN,
  strategy: Strategy.UI,
  browser: true,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open the automation browser and sign in to LinkedIn again (verify JSESSIONID cookie exists and is fresh) — the code already checks this at line 144-149, so a 401 despite the cookie means rotation mid-run: re-run the command.
  2. Confirm the account actually has an active Sales Navigator license (Settings → Sales Navigator); a 403 on sales-api usually means no entitlement.
  3. Log in to https://www.linkedin.com/sales/ manually once in the same browser profile to establish the Sales Navigator session, then retry.
  4. Slow down / add delay between page requests — aggressive pagination can trigger 403 throttling.
  5. Check whether LinkedIn changed sales-api access; try the same query in the Sales Navigator UI to confirm the account works interactively.

Example fix

// before (retrying blindly with a stale session)
const result = unwrapEvaluateResult(await page.evaluate(fetchLeadSearchScript(url, csrf)));
const json = requireLeadSearchResult(result);
// after
catch (e) {
  if (e instanceof AuthRequiredError) {
    await page.goto(SALES_HOME);
    await page.wait(10); // give user/login flow time to (re)establish session, then retry once
    const retry = unwrapEvaluateResult(await page.evaluate(fetchLeadSearchScript(url, csrf)));
    const json = requireLeadSearchResult(retry);
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before invoking, confirm session prerequisites in your own harness:
const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });
const hasSession = cookies.some((c) => c.name === 'JSESSIONID');
// and confirm Sales Navigator access by loading:
// https://www.linkedin.com/sales/ and checking it does not redirect to a paywall/login

Type guard

function isAuthFailure(result) {
  return !!result && typeof result === 'object' && result.authRequired === true;
}

Try / catch

import { AuthRequiredError } from '@jackwener/opencli/errors';
try {
  const json = requireLeadSearchResult(result);
} catch (e) {
  if (e instanceof AuthRequiredError) {
    // prompt re-login in the automation browser, then retry the command once
    console.error('Sales Navigator session invalid or missing entitlement:', e.message);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: The cli 'salesnav-search' command evaluates fetchLeadSearchScript in the page and the response status is 401 (stale/expired JSESSIONID csrf token or logged-out session) or 403 (logged in but no Sales Navigator seat, or LinkedIn blocking the sales-api call).

Common situations: LinkedIn session expired or was logged out between commands; CSRF token mismatch after JSESSIONID rotation; account downgraded or trial of Sales Navigator ended; LinkedIn rate-limiting or temporarily blocking sales-api requests with 403; corporate SSO session requiring re-login.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/0776a579ee764349. Report an issue: GitHub.