jackwener/OpenCLI · error · CommandExecutionError

Sales Navigator lead search API returned malformed payload

Error message

Sales Navigator lead search API returned malformed payload

What it means

parseLeads validates the JSON returned by the Sales Navigator lead search API: it must be an object with an elements array, and each element must be an object. Any deviation throws CommandExecutionError because search results cannot be parsed.

Source

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

}

// Sales Navigator search returns no /in/ vanity URL, but the entityUrn carries
// the obfuscated member token, and linkedin.com/in/<token> is a valid profile
// URL that the connect command accepts.
function profileUrlFromEntityUrn(entityUrn) {
  const match = String(entityUrn || '').match(/fs_salesProfile:\(([^,)]+)/);
  return match && match[1] ? 'https://www.linkedin.com/in/' + match[1] : '';
}

function leadUrlFromEntityUrn(entityUrn) {
  const match = String(entityUrn || '').match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);
  if (!match) return '';
  return `https://www.linkedin.com/sales/lead/${encodeURIComponent(match[1])},${encodeURIComponent(match[2])},${encodeURIComponent(match[3])}`;
}

function parseLeads(json) {
  if (!json || typeof json !== 'object' || !Array.isArray(json.elements)) {
    throw new CommandExecutionError('Sales Navigator lead search API returned malformed payload');
  }
  const leads = [];
  for (const el of json.elements) {
    if (!el || typeof el !== 'object') {
      throw new CommandExecutionError('Sales Navigator lead search API returned malformed lead row');
    }
    const current = Array.isArray(el.currentPositions) ? el.currentPositions : [];
    const past = Array.isArray(el.pastPositions) ? el.pastPositions : [];
    const pos = current[0] || past[0] || {};
    const name = normalizeWhitespace(el.fullName || [el.firstName, el.lastName].filter(Boolean).join(' '));
    if (!name) {
      throw new CommandExecutionError('Sales Navigator lead row missing name');
    }
    const entityUrn = normalizeWhitespace(el.entityUrn || '');
    if (!profileUrlFromEntityUrn(entityUrn)) {
      throw new CommandExecutionError('Sales Navigator lead row missing profile identity');
    }
    leads.push({

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate (refresh the LinkedIn/ Sales Navigator session and CSRF token) and retry — a login redirect body is the most common malformed payload.
  2. Retry the search once; if the schema genuinely changed, inspect the raw JSON from the fetch result and update parseLeads to the new shape.
  3. Catch the error and surface the raw payload for diagnosis before reporting failure to the end user.

Example fix

// before
const leads = parseLeads(result.json);
// after
let leads;
try {
  leads = parseLeads(result.json);
} catch (e) {
  console.error('Raw payload:', JSON.stringify(result.json).slice(0, 500));
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function looksLikeLeadSearchPayload(json) {
  return !!json && typeof json === 'object' && Array.isArray(json.elements);
}

Type guard

function isLeadSearchPayload(json) {
  return typeof json === 'object' && json !== null && Array.isArray(json.elements) &&
    json.elements.every((el) => el && typeof el === 'object');
}

Try / catch

try {
  leads = parseLeads(result.json);
} catch (e) {
  if (typeof result.raw === 'string' && /login|sign in|authwall/i.test(result.raw)) {
    await reauthenticate();
    return retrySearch();
  }
  throw e;
}

Prevention

When it happens

Trigger: The API returned null/empty JSON, an HTML login/consent page captured by the fetch script, a non-object envelope (e.g. a bare array or error body), or an elements entry that is null/not an object.

Common situations: Expired or missing LinkedIn session/CSRF so the endpoint returns an auth redirect body; Sales Navigator API response schema changed; rate limiting or empty-state responses with a different shape; transient network capture failure inside page.evaluate.

Understand the failure class

Related errors


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