jackwener/OpenCLI · error · AuthRequiredError

${label} auth failed.

Error message

${label} auth failed.

What it means

requireFetchResult normalizes every Sales Navigator fetch response and throws AuthRequiredError when the response body flags authRequired:true. LinkedIn returned a page/JSON indicating the session is no longer authenticated, so the CLI aborts instead of proceeding with unauthenticated API calls. The message identifies which step ('profile', 'credits', 'send', 'credits-after') hit the auth wall via the ${label} placeholder.

Source

Thrown at clis/linkedin/salesnav-message.js:165

      return ['ok', res.status, json, text];
    } catch (e) {
      return ['error', 0, null, '', 'fetch failed: ' + ((e && e.message) || String(e))];
    }
  })()`;
}

function requireFetchResult(result, label, { requireJson = true } = {}) {
  if (Array.isArray(result)) {
    const [kind, status, json, text, error] = result;
    result = {
      authRequired: kind === 'auth',
      error: kind === 'error' ? error || `HTTP ${status}` : '',
      status,
      json,
      text,
    };
  }
  if (result?.authRequired) throw new AuthRequiredError(LINKEDIN_DOMAIN, `${label} auth failed.`);
  if (result?.error) throw new CommandExecutionError(`${label} failed`, result.error);
  if (!result || typeof result !== 'object' || Array.isArray(result)) {
    throw new CommandExecutionError(`${label} returned malformed response`);
  }
  if (requireJson && (!result.json || typeof result.json !== 'object' || Array.isArray(result.json))) {
    throw new CommandExecutionError(`${label} returned malformed response`, 'missing_json');
  }
  return result;
}

function salesPageShowsSentMessage(text, recipientName) {
  const normalizedText = normalizeWhitespace(text);
  const firstName = normalizeWhitespace(recipientName).split(' ')[0];
  return normalizedText.includes('You sent a Sales Navigator message')
    && (!firstName || normalizedText.includes(firstName));
}

async function getCsrf(page) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate the browser session (log into linkedin.com in the automation's browser profile) and re-run the command
  2. Persist and reuse a fresh cookie state so JSESSIONID stays valid between runs
  3. Check the LinkedIn/Sales Nav account is still active and subscribed
  4. Reduce automation pace / avoid concurrent sessions that invalidate each other

Example fix

// before: single long-lived session reused for hours
// after: re-login before batch runs
const page = await browser.newPage();
await signIn(page); // ensures fresh JSESSIONID
const result = await sendInMail(page, args);
Defensive patterns

Strategy: try-catch

Validate before calling

// before running: confirm session cookies exist
const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });
if (!cookies.some((c) => c.name === 'JSESSIONID')) throw new Error('Log in to LinkedIn first');

Type guard

function hasSession(cookies) {
  return Array.isArray(cookies) && cookies.some((c) => c.name === 'JSESSIONID' && c.value);
}

Try / catch

try {
  await cli.run('linkedin', 'salesnav-message', page, args);
} catch (err) {
  if (/auth failed/i.test(err.message)) {
    await reauthenticate(page); // fresh login, then retry once
  } else throw err;
}

Prevention

When it happens

Trigger: Any of the four fetches (profile lookup, credits query, send-message createMessage, post-send credits re-query) returns JSON with authRequired=true — typically because JSESSIONID expired mid-run, the session was logged out elsewhere, or LinkedIn redirected an API call to the login page.

Common situations: Long-running automations outliving cookie lifetime; running from a server/IP LinkedIn treats as suspicious; sharing one account between browser and automation causing session invalidation; Sales Navigator subscription lapsing.

Related errors


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