{"record":{"id":"e15bb9789308f517","repo":"jackwener/OpenCLI","slug":"label-authentication-failed-http-result-stat","errorCode":null,"errorMessage":"${label} authentication failed (HTTP ${result.status || 'auth_required'}).","messagePattern":"(.+?) authentication failed \\(HTTP (.+?)\\)\\.","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"critical","filePath":"clis/linkedin/salesnav-inbox.js","lineNumber":127,"sourceCode":"      if (res.status === 401 || res.status === 403) return { authRequired: true, status: res.status, text };\n      if (!res.ok) return { error: 'HTTP ' + res.status, status: res.status, text, json };\n      return { status: res.status, json };\n    } catch (e) {\n      return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };\n    }\n  })()`;\n}\n\nexport async function getCsrf(page) {\n  const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });\n  const jsession = cookies.find((c) => c.name === 'JSESSIONID')?.value;\n  if (!jsession) throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.');\n  return jsession.replace(/^\\\"|\\\"$/g, '');\n}\n\nexport async function fetchSalesnavJson(page, csrf, url, label) {\n  const result = unwrapEvaluateResult(await page.evaluate(fetchJsonScript(url, csrf)));\n  if (result?.authRequired) throw new AuthRequiredError(LINKEDIN_DOMAIN, `${label} authentication failed (HTTP ${result.status || 'auth_required'}).`);\n  if (result?.error || !result?.json) throw new CommandExecutionError(`${label} returned an unexpected response`, `${result?.error || 'no_json'}\\n${normalizeWhitespace(result?.text || '').slice(0, 500)}`);\n  return result.json;\n}\n\nexport async function fetchInboxRows(page, { limit = DEFAULT_LIMIT, maxPages = 30 } = {}) {\n  const csrf = await getCsrf(page);\n  const rows = [];\n  const seen = new Set();\n  let pageStartsAt = '';\n  let pagesFetched = 0;\n  let hasMorePages = false;\n  while (rows.length < limit && pagesFetched < maxPages) {\n    const json = await fetchSalesnavJson(page, csrf, threadListUrl({ count: PAGE_SIZE, pageStartsAt }), 'Sales Navigator messaging threads API');\n    pagesFetched += 1;\n    const pageRows = parseSalesnavThreads(json);\n    if (pageRows.length === 0) break;\n    for (const row of pageRows) {\n      if (seen.has(row.thread_id)) continue;","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/salesnav-inbox.js#L109-L145","documentation":"This AuthRequiredError is thrown by fetchSalesnavJson when the in-page fetch reports authRequired — Sales Navigator returned an authentication failure (HTTP 401/403 or a redirect to login) instead of thread JSON, even though a CSRF token was found.","triggerScenarios":"Calling fetchSalesnavJson (via fetchInboxRows/json/fetchThreadWithPagination) when the LinkedIn session became invalid between getting the CSRF cookie and the API call — the endpoint replies with 401/403 or an auth redirect detected by the fetch script.","commonSituations":"Session expired mid-run (long scrapes); LinkedIn invalidated the session server-side; Sales Navigator license/lacking entitlement for the messaging endpoint; rate limiting that presents as an auth challenge.","solutions":["Re-authenticate / sign in again and restart the scrape with a fresh session","Shorten run duration and persist/refresh cookies so long jobs re-validate the session","Verify the account has active Sales Navigator access to the messaging API","Back off and retry later if LinkedIn is throttling the account"],"exampleFix":"// before\nawait fetchInboxRows(page); // may fail mid-run on expiry\n// after\ntry {\n  await fetchInboxRows(page);\n} catch (e) {\n  if (e instanceof AuthRequiredError) { await relogin(page); await fetchInboxRows(page); }\n  else throw e;\n}","handlingStrategy":"retry","validationCode":"const csrf = await getCsrf(page);\nif (!csrf) throw new Error('No CSRF token; sign in to LinkedIn Sales Navigator first');","typeGuard":"null","tryCatchPattern":"try {\n  const rows = await fetchInboxRows(page);\n} catch (e) {\n  if (String(e.message).includes('authentication failed')) {\n    await relogin(page); // refresh session + cookies\n    return fetchInboxRows(page);\n  }\n  throw e;\n}","preventionTips":["Refresh the session before long-running scrapes","Verify the account has an active Sales Navigator license","Add exponential backoff for 401/403 responses","Monitor session health mid-run and re-login proactively"],"tags":["linkedin","sales-navigator","authentication","http-401"],"backgroundTag":"http-401-unauthorized","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}