jackwener/OpenCLI · error · CommandExecutionError

LinkedIn job detail returned malformed extraction payload

Error message

LinkedIn job detail returned malformed extraction payload

What it means

normalizeDetail validates the raw row produced by the in-page extraction script before mapping it to the output shape. If the evaluated script returned null, undefined, or a non-object (extraction failed entirely), a CommandExecutionError is thrown describing the payload as malformed. This keeps downstream field normalization from crashing on a missing object.

Source

Thrown at clis/linkedin/job-detail.js:121

    return {
      url: location.href,
      title: h1,
      company,
      company_url,
      location: locationLine,
      workplace_type: workplaceMatch ? workplaceMatch[1] : '',
      job_type: jobTypeMatch ? jobTypeMatch[1] : '',
      applicants: applicantsMatch ? applicantsMatch[1] : '',
      listed: listedMatch ? listedMatch[1] : '',
      apply_url,
      description,
    };
  })()`;
}

function normalizeDetail(row) {
  if (!row || typeof row !== 'object') {
    throw new CommandExecutionError('LinkedIn job detail returned malformed extraction payload');
  }
  const title = normalizeWhitespace(row.title);
  if (!title) throw new CommandExecutionError('LinkedIn job detail could not find a job title');
  return {
    title,
    company: normalizeWhitespace(row.company),
    location: normalizeWhitespace(row.location),
    workplace_type: normalizeWhitespace(row.workplace_type),
    job_type: normalizeWhitespace(row.job_type),
    applicants: normalizeWhitespace(row.applicants),
    listed: normalizeWhitespace(row.listed),
    apply_url: decodeLinkedinRedirect(normalizeWhitespace(row.apply_url)),
    company_url: normalizeHttpUrl(row.company_url),
    url: normalizeHttpUrl(row.url),
    description: normalizeWhitespace(row.description),
  };
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command; transient timing issues where the page hadn't finished rendering are the most common cause.
  2. Open the job URL in the browser to confirm the posting still exists and renders a detail view.
  3. Verify the session can view the job (some jobs require sign-in or region access).
  4. If the page renders fine manually but the error persists, the extraction selectors are stale — update/report the library.

Example fix

// before
const d = jobDetail(url); // CommandExecutionError: malformed payload (page slow)

// after
await page.goto(url); await waitForSelector('.job-details');
const d = jobDetail(url);
Defensive patterns

Strategy: retry

Validate before calling

// before invoking, ensure the job page actually rendered a detail section
await page.goto(jobUrl);
await page.waitForSelector('[class*="job-details"], .jobs-details', { timeout: 15000 });

Type guard

const isMalformedPayloadError = (e) => e instanceof CommandExecutionError && /malformed extraction payload/i.test(e?.message || '');

Try / catch

try {
  return await linkedinJobDetail(jobUrl);
} catch (e) {
  if (isMalformedPayloadError(e)) {
    await sleep(3000);
    return retry(linkedinJobDetail, { args: [jobUrl], attempts: 2 });
  }
  throw e;
}

Prevention

When it happens

Trigger: During `linkedin job-detail`, the injected extraction script returns no object — the job page didn't render its detail section, a selector missed, the page showed an error/login wall, or evaluate returned an unwrapped null.

Common situations: Job posting removed/expired so the page renders a 'no longer available' state, page still loading when extraction ran (timing), LinkedIn DOM restructure changing selectors, or a login wall replacing the detail content.

Understand the failure class

Related errors


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