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
- Re-authenticate (refresh the LinkedIn/ Sales Navigator session and CSRF token) and retry — a login redirect body is the most common malformed payload.
- Retry the search once; if the schema genuinely changed, inspect the raw JSON from the fetch result and update parseLeads to the new shape.
- 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
- Verify session/CSRF validity before long search jobs
- Log the raw response payload when parsing fails
- Pin/monitor LinkedIn API response shape in CI with a recorded fixture
- Retry once on transient failures before surfacing the error
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Sales Navigator messaging threads API returned malformed pay
- Sales Navigator messaging threads API returned malformed thr
- ${label} returned an unexpected response
- ${label} returned malformed response
- Sales Navigator lead search API returned malformed lead row
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1575e6b10ed4e0de.
Report an issue: GitHub.