{"record":{"id":"ece15e883b49684e","repo":"jackwener/OpenCLI","slug":"linkedin-people-search-returned-row-without-stable","errorCode":null,"errorMessage":"LinkedIn people search returned row without stable profile identity at index ${index}","messagePattern":"LinkedIn people search returned row without stable profile identity at index (.+?)","errorType":"error_code","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/people-search.js","lineNumber":60,"sourceCode":"        if (!match || !match[1]) return '';\n        return `https://www.linkedin.com/in/${match[1]}/`;\n    } catch {\n        return '';\n    }\n}\n\nfunction normalizePeopleRows(rows) {\n    if (!Array.isArray(rows)) {\n        throw new CommandExecutionError('LinkedIn people search returned malformed extraction payload: missing rows array');\n    }\n    return rows.map((row, index) => {\n        if (!row || typeof row !== 'object') {\n            throw new CommandExecutionError(`LinkedIn people search returned malformed row at index ${index}`);\n        }\n        const name = normalizeWhitespace(row.name);\n        const profileUrl = normalizeProfileUrl(row.profile_url);\n        if (!name || !profileUrl) {\n            throw new CommandExecutionError(`LinkedIn people search returned row without stable profile identity at index ${index}`);\n        }\n        return {\n            name,\n            headline: normalizeWhitespace(row.headline),\n            location: normalizeWhitespace(row.location),\n            profile_url: profileUrl,\n        };\n    });\n}\n\nfunction parseNonNegativeCount(value, label) {\n    const count = Number(value);\n    if (!Number.isInteger(count) || count < 0) {\n        throw new CommandExecutionError(`LinkedIn people search returned malformed extraction payload: invalid ${label}`);\n    }\n    return count;\n}\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/people-search.js#L42-L78","documentation":"CommandExecutionError thrown by normalizePeopleRows when a row lacks a stable identity: after normalization both name and profile_url are empty/missing. Identity fields are mandatory because downstream consumers key results off them, so rows without either are rejected with the index in the message.","triggerScenarios":"A scraped row where row.name normalizes to '' or row.profile_url fails normalizeProfileUrl — e.g. rows from a results DOM variant with the name in a different node, or profile links rendered as relative/obfuscated URLs the normalizer rejects.","commonSituations":"LinkedIn serves different card markup for some results (e.g. company cards mixed into people results); privacy-restricted profiles hiding the name; normalizeProfileUrl too strict for new link formats (e.g. /in/name/ vs new tracking-wrapped URLs).","solutions":["Update the extraction script to target the current name and profile-link selectors","Relax/extend normalizeProfileUrl to accept the new URL form and resolve relative links","Skip identity-less rows instead of failing the whole batch","Wait longer before extraction so lazy-loaded name/link elements are present"],"exampleFix":"// before\nif (!name || !profileUrl) {\n  throw new CommandExecutionError(`LinkedIn people search returned row without stable profile identity at index ${index}`);\n}\n// after\nif (!name || !profileUrl) {\n  console.warn(`skipping row ${index}: missing identity`);\n  return null;\n}\n... .filter(Boolean);","handlingStrategy":"validation","validationCode":"function hasStableIdentity(row) {\n  const name = (row && typeof row.name === 'string') ? row.name.trim() : '';\n  const url = (row && typeof row.profile_url === 'string') ? row.profile_url.trim() : '';\n  return Boolean(name && url);\n}\nconst usable = rawRows.filter(hasStableIdentity);","typeGuard":"function isIdentifiedPerson(row) {\n  return typeof row === 'object' && row !== null && typeof row.name === 'string' && row.name.trim() !== '' && typeof row.profile_url === 'string' && row.profile_url.trim() !== '';\n}","tryCatchPattern":"try {\n  return normalizePeopleRows(rows);\n} catch (err) {\n  const m = String(err.message).match(/without stable profile identity at index (\\d+)/);\n  if (m) {\n    rows.splice(Number(m[1]), 1);\n    return normalizePeopleRows(rows);\n  }\n  throw err;\n}","preventionTips":["Keep extraction selectors for name and profile URL current with LinkedIn's card markup","Extend normalizeProfileUrl to accept new/relative link formats","Skip privacy-restricted profiles without names rather than failing the batch","Wait for lazy-loaded identity fields before evaluating the extraction script"],"tags":["linkedin","schema-validation","scraping"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}