jackwener/OpenCLI · error · CommandExecutionError
LinkedIn jobs preferences returned malformed preferences pay
Error message
LinkedIn jobs preferences returned malformed preferences payload
What it means
Thrown by normalizePreferences when the preferences payload scraped from LinkedIn's job preferences page is not a non-null object. The extraction script returns whatever the DOM evaluate produced, and this guard rejects null/undefined/non-object results before field normalization. It means the page's structured data could not be extracted in the expected shape.
Source
Thrown at clis/linkedin/jobs-preferences.js:65
const lines = text.split(/\n+/).map(clean).filter(Boolean);
const alerts = [];
for (let i = 0; i < lines.length; i++) {
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),
};View on GitHub (pinned to 49907e53dc)
Solutions
- Re-authenticate (refresh valid LinkedIn cookies) so the real preferences page loads
- Increase the wait time after page.goto(PREFERENCES_URL) so dynamic content renders
- Inspect the raw evaluate output and update buildPreferencesScript() to match current LinkedIn DOM/JSON structure
- Log the payload before normalizePreferences to confirm whether authwall or markup change caused it
Example fix
// before
const preferences = unwrapEvaluateResult(await page.evaluate(buildPreferencesScript()));
return out(normalizePreferences(preferences, alerts));
// after
const preferences = unwrapEvaluateResult(await page.evaluate(buildPreferencesScript()));
if (!preferences || typeof preferences !== 'object') {
await page.screenshot({ path: 'preferences-debug.png' });
}
return out(normalizePreferences(preferences, alerts)); Defensive patterns
Strategy: type-guard
Validate before calling
const prefs = unwrapEvaluateResult(await page.evaluate(buildPreferencesScript()));
if (!prefs || typeof prefs !== 'object' || Array.isArray(prefs)) {
await page.screenshot({ path: 'prefs-debug.png' });
throw new Error('preferences extraction returned non-object — likely authwall or DOM change');
} Type guard
function isPreferencesPayload(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v) && ('raw_preferences' in v || 'job_titles' in v);
} Try / catch
try {
return normalizePreferences(preferences, alerts);
} catch (err) {
if (String(err.message).includes('malformed preferences payload')) {
await assertLinkedInAuthenticated(page, 'preferences');
// retry extraction once after re-auth / longer wait
} else throw err;
} Prevention
- Verify authentication before evaluating extraction scripts
- Use generous waits after page.goto for LinkedIn's dynamic content
- Pin/monitor LinkedIn DOM changes; test the extraction script after LinkedIn UI updates
- Log raw evaluate output in debug mode for post-mortem
When it happens
Trigger: page.evaluate(buildPreferencesScript()) returning null, undefined, a string, or an array because the preferences page DOM/JSON blob was absent, or unwrapEvaluateResult returning a non-object.
Common situations: LinkedIn served a login/authwall or CAPTCHA page instead of preferences so the script found no data; LinkedIn changed its preferences page markup breaking the extraction script; page.wait(5) was too short and data hadn't rendered.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- LinkedIn jobs preferences returned malformed alerts payload
- LinkedIn people search returned malformed extraction payload
- LinkedIn people search returned malformed row at index ${ind
- LinkedIn people search returned row without stable profile i
- LinkedIn messengerMessages API returned a malformed page wra
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/fddf6c3486e2f42b.
Report an issue: GitHub.