{"record":{"id":"0776a579ee764349","repo":"jackwener/OpenCLI","slug":"linkedin-sales-navigator-api-auth-failed-http","errorCode":null,"errorMessage":"LinkedIn Sales Navigator API auth failed (HTTP ' + (result.status || '') + '). Confirm the account has Sales Navigator access.","messagePattern":"LinkedIn Sales Navigator API auth failed \\(HTTP ' \\+ \\(result\\.status \\|\\| ''\\) \\+ '\\)\\. Confirm the account has Sales Navigator access\\.","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"critical","filePath":"clis/linkedin/salesnav-search.js","lineNumber":112,"sourceCode":"      throw new CommandExecutionError('Sales Navigator lead row missing profile identity');\n    }\n    leads.push({\n      name,\n      title: normalizeWhitespace(pos.title || ''),\n      company: normalizeWhitespace(pos.companyName || ''),\n      location: normalizeWhitespace(el.geoRegion || ''),\n      degree: normalizeWhitespace(el.degree || ''),\n      profile_url: profileUrlFromEntityUrn(entityUrn),\n      lead_url: leadUrlFromEntityUrn(entityUrn),\n      recipient_urn: entityUrn,\n    });\n  }\n  return leads;\n}\n\nfunction requireLeadSearchResult(result) {\n  if (result?.authRequired) {\n    throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn Sales Navigator API auth failed (HTTP ' + (result.status || '') + '). Confirm the account has Sales Navigator access.');\n  }\n  if (result?.error) {\n    throw new CommandExecutionError('Sales Navigator lead search API returned an unexpected response', result.error);\n  }\n  if (!result || !result.json) {\n    throw new CommandExecutionError('Sales Navigator lead search API returned an unexpected response', 'no_json');\n  }\n  return result.json;\n}\n\ncli({\n  site: 'linkedin',\n  name: 'salesnav-search',\n  access: 'read',\n  description: 'Search LinkedIn Sales Navigator for people leads by keyword',\n  domain: LINKEDIN_DOMAIN,\n  strategy: Strategy.UI,\n  browser: true,","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-search.js#L94-L130","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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.","Confirm the account actually has an active Sales Navigator license (Settings → Sales Navigator); a 403 on sales-api usually means no entitlement.","Log in to https://www.linkedin.com/sales/ manually once in the same browser profile to establish the Sales Navigator session, then retry.","Slow down / add delay between page requests — aggressive pagination can trigger 403 throttling.","Check whether LinkedIn changed sales-api access; try the same query in the Sales Navigator UI to confirm the account works interactively."],"exampleFix":"// before (retrying blindly with a stale session)\nconst result = unwrapEvaluateResult(await page.evaluate(fetchLeadSearchScript(url, csrf)));\nconst json = requireLeadSearchResult(result);\n// after\ncatch (e) {\n  if (e instanceof AuthRequiredError) {\n    await page.goto(SALES_HOME);\n    await page.wait(10); // give user/login flow time to (re)establish session, then retry once\n    const retry = unwrapEvaluateResult(await page.evaluate(fetchLeadSearchScript(url, csrf)));\n    const json = requireLeadSearchResult(retry);\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":"// before invoking, confirm session prerequisites in your own harness:\nconst cookies = await page.getCookies({ url: 'https://www.linkedin.com' });\nconst hasSession = cookies.some((c) => c.name === 'JSESSIONID');\n// and confirm Sales Navigator access by loading:\n// https://www.linkedin.com/sales/ and checking it does not redirect to a paywall/login","typeGuard":"function isAuthFailure(result) {\n  return !!result && typeof result === 'object' && result.authRequired === true;\n}","tryCatchPattern":"import { AuthRequiredError } from '@jackwener/opencli/errors';\ntry {\n  const json = requireLeadSearchResult(result);\n} catch (e) {\n  if (e instanceof AuthRequiredError) {\n    // prompt re-login in the automation browser, then retry the command once\n    console.error('Sales Navigator session invalid or missing entitlement:', e.message);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always sign in to LinkedIn (and open /sales/ once) in the automation browser profile before running searches.","Keep the Sales Navigator subscription active — 403 means no entitlement even with a valid session.","Re-authenticate when JSESSIONID expires; long-running jobs should re-check cookies per run.","Space out search requests to avoid LinkedIn soft-blocking sales-api with 403.","Catch AuthRequiredError distinctly from CommandExecutionError so login issues are surfaced to the user."],"tags":["authentication","http-401","http-403","sales-navigator","session-expired"],"backgroundTag":"linkedin-auth-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}