jackwener/OpenCLI · error · CommandExecutionError
LinkedIn Learning searchV2 returned malformed payload: missi
Error message
LinkedIn Learning searchV2 returned malformed payload: missing elements array
What it means
Thrown when the searchV2 API responds with valid JSON but that JSON lacks an 'elements' array at the top level. The CLI expects a RestLi-style collection payload; anything else (an error envelope, an HTML/JSON hybrid, or a changed schema) is treated as malformed. This guards the row-parsing loop from crashing on unexpected shapes.
Source
Thrown at clis/linkedin-learning/search.js:76
args: [
{ name: 'keywords', type: 'string', required: true, positional: true, help: 'Search keywords, e.g. "AI agent"' },
{ name: 'limit', type: 'int', default: 10, help: `Maximum results to return (1-${MAX_LIMIT})` },
],
columns: ['rank', 'type', 'title', 'instructor', 'difficulty', 'duration_sec', 'rating', 'rating_count', 'viewers', 'url'],
func: async (page, args) => {
if (!page) throw new CommandExecutionError('Browser session required for linkedin-learning search');
const keywords = normalizeWhitespace(args.keywords);
if (!keywords) throw new ArgumentError('--keywords is required');
const limit = parseLimit(args.limit);
const url = `https://www.linkedin.com/learning-api/searchV2?keywords=${encodeURIComponent(keywords)}&q=keywords`;
const result = await fetchLinkedInLearningApi(page, url);
if (!result?.json) {
throw new CommandExecutionError(`LinkedIn Learning searchV2 failed: ${result?.error ?? 'no payload'}`);
}
const elements = result.json?.elements;
if (!Array.isArray(elements)) {
throw new CommandExecutionError('LinkedIn Learning searchV2 returned malformed payload: missing elements array');
}
if (elements.length === 0) {
throw new EmptyResultError(`No LinkedIn Learning results for "${keywords}"`);
}
const rows = [];
for (const el of elements) {
if (rows.length >= limit) break;
const row = parseRow(el, rows.length + 1);
if (row) rows.push(row);
}
if (rows.length === 0) {
throw new CommandExecutionError('LinkedIn Learning searchV2 returned no parseable rows with slug identity');
}
return rows;
},
});
export const __test__ = {View on GitHub (pinned to 49907e53dc)
Solutions
- Log result.json keys to inspect the actual payload shape and confirm schema drift.
- Update the CLI to the latest version that matches the current LinkedIn searchV2 schema.
- Add a fallback to parse alternate payload shapes (e.g. result.json.data?.elements or included arrays).
- Check LinkedIn Learning in the browser to see if search still works (indicates an API-side change, not local config).
Example fix
// before
const elements = result.json?.elements;
if (!Array.isArray(elements)) throw new CommandExecutionError('...missing elements array');
// after
const raw = result.json?.elements ?? result.json?.data?.elements;
if (!Array.isArray(raw)) throw new CommandExecutionError('...missing elements array: keys=' + Object.keys(result.json ?? {}).join(',')); Defensive patterns
Strategy: type-guard
Validate before calling
// after fetch, validate expected RestLi shape before consuming
if (!result?.json || !Array.isArray(result.json.elements)) {
throw new Error('Unexpected searchV2 payload: ' + JSON.stringify(result?.json)?.slice(0, 200));
} Type guard
function isSearchV2Payload(json) {
return !!json && typeof json === 'object' && Array.isArray(json.elements) &&
json.elements.every(el => el && typeof el === 'object');
} Try / catch
try {
const rows = await search(page, { keywords });
} catch (e) {
if (e.message.includes('malformed payload')) {
console.error('LinkedIn schema drift detected; update the CLI or inspect payload', e.message);
} else throw e;
} Prevention
- Keep the CLI updated — internal LinkedIn APIs change without notice
- Log payload keys when the guard fires to detect schema drift early
- Pin/monitor CLI versions in CI so failures correlate with upgrades
- Fall back to alternate payload shapes (data.elements / included) defensively
When it happens
Trigger: result.json exists but result.json.elements is not an Array — e.g. the endpoint returned {'status':404,'message':...} style RestLi error JSON, an included/wrapper object, or LinkedIn changed the searchV2 response schema.
Common situations: LinkedIn deprecating or reshaping the internal searchV2 API (schema drift), the endpoint returning an error envelope with HTTP 200, or an A/B-tested variant payload without elements.
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 Learning feedRecommendationGroups returned malforme
- LinkedIn Learning searchV2 returned no parseable rows with s
- ${label} returned an unexpected payload shape; expected an o
- ${label} returned an unexpected payload shape; expected an a
- ${label} did not include a stable ${field}.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ab549f0f290f6c7f.
Report an issue: GitHub.