jackwener/OpenCLI · error · CommandExecutionError

LinkedIn company extraction ended outside a company page

Error message

LinkedIn company extraction ended outside a company page

What it means

Even when the final URL is on linkedin.com, the path must still match COMPANY_URL_RE with a captured slug. If the browser ended outside a /company/<name> path (feed, login, search results, redirected company page), this error is thrown because no company slug can be extracted.

Solutions

  1. Verify the company slug exists by opening the URL in a browser first
  2. Wait for the SPA to finish navigating before running extraction (or retry the command)
  3. Re-authenticate the scraping session to avoid authwall redirects
  4. Use the canonical /company/<slug>/about/ URL as targetUrl
Defensive patterns

Strategy: retry

Validate before calling

function isCompanyAboutUrl(u) { try { return /\/company\/[^/]+/.test(new URL(u).pathname); } catch { return false; } }
// pre-check the target before invoking
if (!isCompanyAboutUrl(target)) throw new Error('Target must be a /company/<slug> URL');

Try / catch

try {
  const info = await company({ url: target });
} catch (err) {
  if (String(err.message).includes('outside a company page')) {
    await wait(2000); // allow SPA navigation to settle
    return company({ url: target });
  }
  throw err;
}

Prevention

When it happens

Trigger: Company page redirected to the LinkedIn feed, authwall, or homepage because the session was unauthenticated or the company does not exist; extraction ran while the SPA was still navigating so location.pathname was not yet /company/...; slug-less URL like /company/ (empty name).

Common situations: Deleted/renamed company slug leading LinkedIn to bounce to a search or feed page; rate-limit or authwall interstitial; scraping too early before client-side routing settled.

Related errors


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

Appendix: source

Thrown at clis/linkedin/company.js:90

      about: about.slice(0, 2000),
    };
  })()`;
}

function normalizeCompanyOutputUrl(value, fallbackUrl) {
    const raw = normalizeWhitespace(value || fallbackUrl);
    let parsed;
    try {
        parsed = new URL(raw, `https://${LINKEDIN_DOMAIN}`);
    } catch {
        throw new CommandExecutionError('LinkedIn company extraction returned a malformed current URL');
    }
    if (parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.port || !LINKEDIN_COMPANY_HOSTS.has(parsed.hostname.toLowerCase())) {
        throw new CommandExecutionError('LinkedIn company extraction ended on a non-LinkedIn page');
    }
    const match = parsed.pathname.match(COMPANY_URL_RE);
    if (!match?.[1]) {
        throw new CommandExecutionError('LinkedIn company extraction ended outside a company page');
    }
    let slug;
    try {
        slug = decodeURIComponent(match[1]);
    } catch {
        throw new CommandExecutionError('LinkedIn company extraction returned a malformed company slug');
    }
    return `https://${LINKEDIN_DOMAIN}/company/${encodeURIComponent(slug)}/about/`;
}

function normalizeCompanyInfo(info, targetUrl) {
    if (!info || typeof info !== 'object' || Array.isArray(info)) {
        throw new CommandExecutionError('LinkedIn company extraction returned a malformed payload');
    }
    if (!info.name) {
        throw new CommandExecutionError('LinkedIn company page rendered but no company name was found (layout drift or company not found)');
    }
    let followers = 0;

View on GitHub (pinned to 49907e53dc)