jackwener/OpenCLI · error · CommandExecutionError
LinkedIn people search returned malformed extraction payload
Error message
LinkedIn people search returned malformed extraction payload: invalid ${label} What it means
parseNonNegativeCount validates numeric extraction-payload fields (candidate_count, person_entries_count, resolved_count) returned by the injected LinkedIn DOM extraction script. If a value is not an integer >= 0, the library assumes the page-side extractor ran in a changed/broken DOM and throws CommandExecutionError naming the bad field via ${label}. This guards downstream row-normalization logic from garbage counts.
Source
Thrown at clis/linkedin/people-search.js:74
}
const name = normalizeWhitespace(row.name);
const profileUrl = normalizeProfileUrl(row.profile_url);
if (!name || !profileUrl) {
throw new CommandExecutionError(`LinkedIn people search returned row without stable profile identity at index ${index}`);
}
return {
name,
headline: normalizeWhitespace(row.headline),
location: normalizeWhitespace(row.location),
profile_url: profileUrl,
};
});
}
function parseNonNegativeCount(value, label) {
const count = Number(value);
if (!Number.isInteger(count) || count < 0) {
throw new CommandExecutionError(`LinkedIn people search returned malformed extraction payload: invalid ${label}`);
}
return count;
}
function extractionScript() {
// Class-based selectors are dead (LinkedIn rotates hashed class
// names on every deploy) and display:contents flattens the DOM
// tree so per-card containers don't exist. Read main.innerText
// and slice between consecutive person-name lines instead.
return String.raw`(() => {
if (!/search\/results\/people/.test(window.location.href)) {
return { error: 'not on people search page', url: window.location.href };
}
const main = document.querySelector('main') || document.body;
const normalize = (s) => String(s || '').replace(/[\s\u00a0\u202f]+/g, ' ').trim();
const collapseRepeatedName = (name) => {
const parts = normalize(name).split(' ').filter(Boolean);
if (parts.length === 0 || parts.length % 2 !== 0) return normalize(name);View on GitHub (pinned to 49907e53dc)
Solutions
- Update the package to the latest version that matches current LinkedIn markup
- Re-run the search in a signed-in browser session so the real results page (with counters) renders
- Log result.candidate_count/result.person_entries_count/result.resolved_count in the evaluate callback to see which field is malformed and why
- Check whether LinkedIn redirected to an auth/CUL page and clear that first (see errors 2345/2348)
- File/inspect the extractionScript() selectors and patch them for the new LinkedIn layout
Example fix
// before: payload field missing, throws const candidateCount = parseNonNegativeCount(result.candidate_count, 'candidate_count'); // after: default missing fields to 0 before validation const candidateCount = parseNonNegativeCount(result.candidate_count ?? 0, 'candidate_count');
Defensive patterns
Strategy: validation
Validate before calling
function isValidCount(v) { return Number.isInteger(Number(v)) && Number(v) >= 0; }
const payload = result ?? {};
if (![payload.candidate_count, payload.person_entries_count, payload.resolved_count].every(isValidCount)) {
throw new Error('extraction payload has invalid count fields');
} Type guard
const isExtractionCounts = (o) => o != null && typeof o === 'object' && ['candidate_count', 'person_entries_count', 'resolved_count'].every((k) => Number.isInteger(Number(o[k])) && Number(o[k]) >= 0);
Try / catch
try { const count = parseNonNegativeCount(result.candidate_count, 'candidate_count'); } catch (e) { logger.warn('malformed counts', result); /* fallback: proceed with rows only */ } Prevention
- Keep the CLI updated against LinkedIn markup changes
- Log raw evaluate payloads before validating counts
- Treat count fields as optional and default to 0 in your own wrappers
- Detect auth/CUL redirects before count validation so the real cause surfaces
When it happens
Trigger: Calling the linkedin people-search command when page.evaluate(extractionScript()) returns a result object whose candidate_count, person_entries_count, or resolved_count is undefined, a non-integer number, negative, or a non-numeric string — e.g. LinkedIn changed the page markup so the counter selectors resolve to nothing.
Common situations: LinkedIn DOM/markup updates breaking the in-page extractor; scraping an empty/interstitial results page; LinkedIn serving a variant layout (different locale or mobile layout); a partial extraction script that sets counts conditionally.
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
- LinkedIn people search returned malformed extraction payload
- LinkedIn people search found profile candidates but could no
- LinkedIn sent invitations returned a malformed extraction pa
- LinkedIn sent invitations contained a malformed invitation c
- LinkedIn services-read returned malformed extraction payload
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f5754c3d1263a485.
Report an issue: GitHub.