{"record":{"id":"e573baff50aed505","repo":"jackwener/OpenCLI","slug":"linkedin-sent-invitations-returned-a-malformed-ext","errorCode":null,"errorMessage":"LinkedIn sent invitations returned a malformed extraction payload.","messagePattern":"LinkedIn sent invitations returned a malformed extraction payload\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/sent-invitations.js","lineNumber":102,"sourceCode":"  description: 'List pending LinkedIn sent invitations for CRM reconciliation',\n  domain: LINKEDIN_DOMAIN,\n  strategy: Strategy.UI,\n  browser: true,\n  args: [],\n  columns: ['rank', 'name', 'profile_url', 'invited_date_text'],\n  func: async (page) => {\n    if (!page) throw new CommandExecutionError('Browser session required for linkedin sent-invitations');\n    await page.goto(SENT_URL);\n    await page.wait(12);\n    let result = unwrapEvaluateResult(await page.evaluate(buildSentInvitationsScript()));\n    if (result?.authRequired) {\n      throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn sent invitations requires an active signed-in browser session.');\n    }\n    if (result?.warning) {\n      throw new CommandExecutionError('LinkedIn warning/restriction state visible on sent invitations page.');\n    }\n    if (!result || typeof result !== 'object' || Array.isArray(result) || !Array.isArray(result.rows)) {\n      throw new CommandExecutionError('LinkedIn sent invitations returned a malformed extraction payload.');\n    }\n    if (result.malformedCount > 0) {\n      throw new CommandExecutionError('LinkedIn sent invitations contained a malformed invitation card.');\n    }\n    const rows = result.rows;\n    if (rows.length === 0) {\n      if (result.explicitEmpty) {\n        throw new EmptyResultError('linkedin sent-invitations', 'No pending sent invitations were found.');\n      }\n      throw new CommandExecutionError('LinkedIn sent invitation cards were not found; the page structure may have changed.');\n    }\n    return rows.map((row, index) => ({\n      rank: index + 1,\n      name: row.name || '',\n      profile_url: row.profile_url || '',\n      invited_date_text: row.invited_date_text || '',\n    }));\n  },","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/sent-invitations.js#L84-L120","documentation":"After auth and warning checks, the command validates the extraction payload shape: it must be a non-null, non-array object whose `rows` property is an array. Anything else means the in-page script did not return the expected structure (serialization problem or unexpected result wrapper) and this CommandExecutionError is thrown.","triggerScenarios":"Running `opencli linkedin sent-invitations` where page.evaluate returns null/undefined, a plain array, or an object without a rows array — e.g. unwrapEvaluateResult failed to normalize the value, the evaluate was cut short, or a wrapper returned an unexpected type.","commonSituations":"Browser automation layer returning serialized values in an unexpected format (version mismatch between CLI and browser driver); a proxy/wrapper around evaluate (unwrapEvaluateResult) failing; page navigation or script error causing evaluate to resolve to undefined; custom modifications to buildSentInvitationsScript returning a different shape.","solutions":["Re-run the command — transient evaluate failures (interrupted script, navigation) usually clear on retry.","Verify the CLI and browser driver versions are compatible; mismatched automation stacks can mangle evaluate return values.","Check whether any customization (unwrapEvaluateResult in shared.js or the extraction script) altered the return contract { rows: [...] }.","Confirm no navigation or page close happens during the 12s wait/evaluate window; keep the tab in the foreground."],"exampleFix":"// before (evaluate returned an array after custom wrapper change)\nreturn cards.map(toRow); // shape break\n// after — preserve the documented payload contract\nreturn { url: href, title: document.title, authRequired, warning, explicitEmpty, rows };\n","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"const isExtractionPayload = (v) =>\n  v !== null && typeof v === 'object' && !Array.isArray(v) && Array.isArray(v.rows);","tryCatchPattern":"try {\n  const rows = await run(['linkedin', 'sent-invitations']);\n} catch (e) {\n  if (/malformed extraction payload/.test(e.message)) {\n    console.error('Extraction returned an unexpected shape — check CLI/driver versions and that the page was not navigated mid-run.');\n    process.exit(4);\n  }\n  throw e;\n}","preventionTips":["Keep the CLI and browser automation driver versions aligned so evaluate return serialization is stable.","Do not navigate or close the page during the extraction window.","If customizing the extraction script, preserve the documented return contract: an object with a rows array.","Treat one retry as acceptable; repeated shape failures indicate a tooling or version problem, not flakiness."],"tags":["linkedin","scraping","payload-validation","browser-automation","serialization"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}