jackwener/OpenCLI · error · CommandExecutionError

LinkedIn services-read returned malformed extraction payload

Error message

LinkedIn services-read returned malformed extraction payload

What it means

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.

Source

Thrown at clis/linkedin/services-read.js:112

      pricing: radios.find((item) => item.checked)?.label || '',
    };
  })()`;
}

function pairsToMedia(items) {
  const lines = Array.isArray(items) ? items.map(normalizeWhitespace).filter(Boolean) : [];
  const pairs = [];
  for (let i = 0; i < lines.length; i += 2) {
    const title = lines[i] || '';
    const description = lines[i + 1] || '';
    if (title) pairs.push(description ? `${title} — ${description}` : title);
  }
  return pairs;
}

function normalizeServices(row) {
  if (!row || typeof row !== 'object') {
    throw new CommandExecutionError('LinkedIn services-read returned malformed extraction payload');
  }
  const services = Array.isArray(row.services_provided) ? row.services_provided.map(normalizeWhitespace).filter(Boolean) : [];
  const mediaItems = pairsToMedia(row.media_lines);
  const publicMedia = [];
  const serviceUrl = normalizeWhitespace(row.service_url);
  const pageTitle = normalizeWhitespace(row.page_title);
  const overview = normalizeWhitespace(row.overview);
  const availability = normalizeWhitespace(row.availability);
  if (!serviceUrl || (!pageTitle && !overview && services.length === 0)) {
    throw new CommandExecutionError('LinkedIn services-read could not find stable Services page content');
  }
  return {
    service_url: serviceUrl,
    page_title: pageTitle,
    overview,
    availability,
    work_locations: Array.isArray(row.work_locations) ? row.work_locations.map((item) => {
      const text = normalizeWhitespace(item);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the raw evaluate payload before normalizeServices to see what the in-page script actually returned.
  2. Re-run with a fresh browser session; confirm the Services page loads fully before extraction.
  3. Update the extraction script so it always resolves to a row object (even an empty one) and re-check after LinkedIn markup changes.
Defensive patterns

Strategy: type-guard

Type guard

function isServiceRow(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v);
}

Try / catch

try {
  result = await page.evaluate(extractScript);
} catch (e) {
  if (!isServiceRow(unwrapEvaluateResult(raw))) throw new Error('extraction returned non-object payload');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/9b771dd1bdf0935a. Report an issue: GitHub.