{"record":{"id":"9b771dd1bdf0935a","repo":"jackwener/OpenCLI","slug":"linkedin-services-read-returned-malformed-extracti","errorCode":null,"errorMessage":"LinkedIn services-read returned malformed extraction payload","messagePattern":"LinkedIn services-read returned malformed extraction payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/services-read.js","lineNumber":112,"sourceCode":"      pricing: radios.find((item) => item.checked)?.label || '',\n    };\n  })()`;\n}\n\nfunction pairsToMedia(items) {\n  const lines = Array.isArray(items) ? items.map(normalizeWhitespace).filter(Boolean) : [];\n  const pairs = [];\n  for (let i = 0; i < lines.length; i += 2) {\n    const title = lines[i] || '';\n    const description = lines[i + 1] || '';\n    if (title) pairs.push(description ? `${title} — ${description}` : title);\n  }\n  return pairs;\n}\n\nfunction normalizeServices(row) {\n  if (!row || typeof row !== 'object') {\n    throw new CommandExecutionError('LinkedIn services-read returned malformed extraction payload');\n  }\n  const services = Array.isArray(row.services_provided) ? row.services_provided.map(normalizeWhitespace).filter(Boolean) : [];\n  const mediaItems = pairsToMedia(row.media_lines);\n  const publicMedia = [];\n  const serviceUrl = normalizeWhitespace(row.service_url);\n  const pageTitle = normalizeWhitespace(row.page_title);\n  const overview = normalizeWhitespace(row.overview);\n  const availability = normalizeWhitespace(row.availability);\n  if (!serviceUrl || (!pageTitle && !overview && services.length === 0)) {\n    throw new CommandExecutionError('LinkedIn services-read could not find stable Services page content');\n  }\n  return {\n    service_url: serviceUrl,\n    page_title: pageTitle,\n    overview,\n    availability,\n    work_locations: Array.isArray(row.work_locations) ? row.work_locations.map((item) => {\n      const text = normalizeWhitespace(item);","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/services-read.js#L94-L130","documentation":"normalizeServices is the payload validator for services-read extraction. It throws this CommandExecutionError when the evaluate result row is null or not an object, i.e. the in-page extraction script returned something structurally invalid instead of a service record object.","triggerScenarios":"page.evaluate (via unwrapEvaluateResult) returned null, undefined, an array, or a primitive for the services row — e.g. the injected script hit an unexpected page state and returned no object.","commonSituations":"LinkedIn served an interstitial/redirect so the script ran on the wrong document; a page.evaluate serialization failure; a scraper version mismatch where the extraction script's contract changed.","solutions":["Log the raw evaluate payload before normalizeServices to see what the in-page script actually returned.","Re-run with a fresh browser session; confirm the Services page loads fully before extraction.","Update the extraction script so it always resolves to a row object (even an empty one) and re-check after LinkedIn markup changes."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isServiceRow(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  result = await page.evaluate(extractScript);\n} catch (e) {\n  if (!isServiceRow(unwrapEvaluateResult(raw))) throw new Error('extraction returned non-object payload');\n}","preventionTips":["Always unwrap with unwrapEvaluateResult before validating the row.","Have the in-page script resolve to an object even on failure (e.g. {error: ...}).","Log the raw payload when this error fires to diagnose page state."],"tags":["linkedin","scraping","payload-validation","malformed-data"],"backgroundTag":"malformed-extraction-payload","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}