jackwener/OpenCLI · error · CommandExecutionError

LinkedIn jobs preferences returned malformed alerts payload

Error message

LinkedIn jobs preferences returned malformed alerts payload

What it means

Thrown by normalizePreferences when the alerts payload (extracted from LinkedIn's job alerts page) is not a non-null object. Like the preferences guard, it rejects malformed scrape results before reading raw_preferences. The second page navigation (ALERTS_URL) returned something other than the expected object.

Source

Thrown at clis/linkedin/jobs-preferences.js:68

      const line = lines[i];
      if (/alert/i.test(line) && line.length < 160) {
        alerts.push([line, lines[i + 1], lines[i + 2]].filter(Boolean).join(' | '));
      }
    }
    return {
      alerts_url: location.href,
      job_alerts: Array.from(new Set(alerts)).slice(0, 20),
      raw_preferences: clean(text).slice(0, 3000),
    };
  })()`;
}

function normalizePreferences(preferences, alerts) {
  if (!preferences || typeof preferences !== 'object') {
    throw new CommandExecutionError('LinkedIn jobs preferences returned malformed preferences payload');
  }
  if (!alerts || typeof alerts !== 'object') {
    throw new CommandExecutionError('LinkedIn jobs preferences returned malformed alerts payload');
  }
  const preferenceText = normalizeWhitespace(preferences.raw_preferences);
  const alertText = normalizeWhitespace(alerts.raw_preferences);
  if (!preferenceText && !alertText) {
    throw new CommandExecutionError('LinkedIn jobs preferences could not find stable preferences content');
  }
  return {
    open_to_work: inferOpenToWork(`${preferenceText} ${alertText}`),
    job_titles: Array.isArray(preferences.job_titles) ? preferences.job_titles.map(normalizeWhitespace).filter(Boolean).join('; ') : '',
    locations: Array.isArray(preferences.locations) ? preferences.locations.map(normalizeWhitespace).filter(Boolean).join('; ') : '',
    job_alerts: Array.isArray(alerts.job_alerts) ? alerts.job_alerts.map(normalizeWhitespace).filter(Boolean).join('; ') : '',
    preferences_url: normalizeWhitespace(preferences.preferences_url),
    alerts_url: normalizeWhitespace(alerts.alerts_url),
    raw_preferences: preferenceText.slice(0, 1200),
  };
}

cli({

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the session stayed authenticated through the second page.goto(ALERTS_URL)
  2. Increase wait time after navigating to ALERTS_URL
  3. Create/save at least one job alert or update buildAlertsScript() for the empty-state DOM
  4. Log the raw alerts evaluate result to distinguish empty-state vs authwall vs markup change

Example fix

// before
const alerts = unwrapEvaluateResult(await page.evaluate(buildAlertsScript()));
return out(normalizePreferences(preferences, alerts));
// after
const alerts = unwrapEvaluateResult(await page.evaluate(buildAlertsScript()));
if (!alerts || typeof alerts !== 'object') {
  alerts = { raw_preferences: '', job_alerts: [] };
}
return out(normalizePreferences(preferences, alerts));
Defensive patterns

Strategy: type-guard

Validate before calling

const alertData = unwrapEvaluateResult(await page.evaluate(buildAlertsScript()));
if (!alertData || typeof alertData !== 'object' || Array.isArray(alertData)) {
  throw new Error('alerts extraction returned non-object — check ALERTS_URL page load/auth');
}

Type guard

function isAlertsPayload(v) {
  return typeof v === 'object' && v !== null && !Array.isArray(v) && ('raw_preferences' in v || 'job_alerts' in v);
}

Try / catch

try {
  return normalizePreferences(preferences, alerts);
} catch (err) {
  if (String(err.message).includes('malformed alerts payload')) {
    await page.goto(ALERTS_URL);
    await page.wait(8);
    alerts = unwrapEvaluateResult(await page.evaluate(buildAlertsScript()));
  } else throw err;
}

Prevention

When it happens

Trigger: page.evaluate on ALERTS_URL returning null/undefined/primitive because the alerts page didn't load its data (authwall, empty alerts state, DOM change) or unwrapEvaluateResult flattened an unexpected shape.

Common situations: User has never configured job alerts so the alerts page renders no structured payload; redirect to login after cookie expiry mid-run; LinkedIn A/B-tested markup so the extraction script returns null.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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