{"record":{"id":"743cf07c4ebf32cd","repo":"jackwener/OpenCLI","slug":"linkedin-people-search-returned-malformed-extracti","errorCode":null,"errorMessage":"LinkedIn people search returned malformed extraction payload: missing rows array","messagePattern":"LinkedIn people search returned malformed extraction payload: missing rows array","errorType":"error_code","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/people-search.js","lineNumber":51,"sourceCode":"function normalizeProfileUrl(value) {\n    const raw = normalizeWhitespace(value);\n    if (!raw) return '';\n    try {\n        const parsed = new URL(raw);\n        const host = parsed.hostname.toLowerCase();\n        if (parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.port) return '';\n        if (host !== 'linkedin.com' && host !== 'www.linkedin.com') return '';\n        const match = parsed.pathname.match(/^\\/in\\/([^/?#]+)\\/?$/);\n        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}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/people-search.js#L33-L69","documentation":"CommandExecutionError thrown by normalizePeopleRows when the payload extracted from the people-search results page is not an array. The extraction script is expected to return an array of row objects; anything else (null, object, string) indicates the scrape failed to find result rows in the expected structure.","triggerScenarios":"page.evaluate returning a non-array because the search results list was absent — authwall/guest page, zero results rendering a different DOM, or LinkedIn markup change breaking the rows collector.","commonSituations":"Expired cookies redirecting to login; search query with no matches producing an empty-state DOM the script can't collect; LinkedIn search UI redesign; insufficient wait before evaluate.","solutions":["Re-authenticate so the authenticated search page loads","Increase the wait after navigating to SEARCH_URL_BASE so results render","Handle the zero-results case by returning [] when the empty-state DOM is detected and update the extraction script for current markup","Log the raw evaluate payload to confirm which shape came back"],"exampleFix":"// before\nconst rows = unwrapEvaluateResult(await page.evaluate(buildSearchScript()));\nreturn normalizePeopleRows(rows);\n// after\nconst raw = unwrapEvaluateResult(await page.evaluate(buildSearchScript()));\nconst rows = Array.isArray(raw) ? raw : (raw && Array.isArray(raw.rows) ? raw.rows : []);\nreturn normalizePeopleRows(rows);","handlingStrategy":"type-guard","validationCode":"const raw = unwrapEvaluateResult(await page.evaluate(buildSearchScript()));\nif (!Array.isArray(raw)) {\n  console.error('extraction did not return an array — check auth page redirect or empty results');\n}","typeGuard":"function isRowsArray(v) {\n  return Array.isArray(v) && v.every((r) => r && typeof r === 'object');\n}","tryCatchPattern":"try {\n  return normalizePeopleRows(rows);\n} catch (err) {\n  if (String(err.message).includes('missing rows array')) {\n    await assertLinkedInAuthenticated(page, 'people search');\n    await page.wait(5);\n    rows = unwrapEvaluateResult(await page.evaluate(buildSearchScript()));\n    return normalizePeopleRows(rows);\n  }\n  throw err;\n}","preventionTips":["Confirm authentication before scraping search results","Increase the post-navigation wait so results render","Handle zero-result searches distinctly (empty-state DOM returns a different shape)","Test the extraction script whenever LinkedIn updates its search UI"],"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"}