jackwener/OpenCLI · error · CommandExecutionError
LinkedIn Learning courses lookup returned malformed course d
Error message
LinkedIn Learning courses lookup returned malformed course detail: missing title
What it means
A course element was returned for the slug, but parseCourse returned null because normalizeWhitespace(el.title) was empty. Since the CLI's primary column is the title, the library treats a title-less course element as a malformed course detail rather than emitting an empty row.
Source
Thrown at clis/linkedin-learning/course.js:89
if (!page) throw new CommandExecutionError('Browser session required for linkedin-learning course');
const slug = parseSlug(args.slug);
const url = `https://www.linkedin.com/learning-api/courses?q=slug&slug=${encodeURIComponent(slug)}`;
const result = await fetchLinkedInLearningApi(page, url);
if (!result?.json) {
throw new CommandExecutionError(`LinkedIn Learning courses lookup failed: ${result?.error ?? 'no payload'}`);
}
const elements = result.json?.elements;
if (!Array.isArray(elements)) {
throw new CommandExecutionError('LinkedIn Learning courses lookup returned malformed payload: missing elements array');
}
const el = elements[0];
if (!el) {
throw new EmptyResultError(`No LinkedIn Learning course found for slug "${slug}"`);
}
const row = parseCourse(el, slug);
if (!row) {
throw new CommandExecutionError('LinkedIn Learning courses lookup returned malformed course detail: missing title');
}
return [row];
},
});
export const __test__ = { parseSlug, parseCourse };
View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw element payload (result.json.elements[0]) to see where the title actually lives.
- Retry or pick a different slug — the entry may be a restricted/placeholder course.
- If LinkedIn changed the schema, update parseCourse to the new title location and update the library.
- Search for the course by title to confirm the correct, fully published slug.
Defensive patterns
Strategy: try-catch
Validate before calling
// No caller-side pre-check possible; requires inspecting the API element. // Log the raw element to diagnose: console.debug(JSON.stringify(rawCourseElement?.title));
Type guard
function hasTitle(el) {
return el != null && typeof el.title === 'string' && el.title.trim().length > 0;
} Try / catch
try {
return await runCommand('linkedin-learning', 'course', [slug]);
} catch (e) {
if (e.message.includes('malformed course detail')) {
return runCommand('linkedin-learning', 'search', [slugToKeywords(slug)]); // get a better-shaped row
}
throw e;
} Prevention
- Fall back to search results (which include titles) when detail parsing fails.
- Skip slugs that repeatedly return title-less elements (likely restricted placeholders).
- Track LinkedIn payload-shape changes and update parsing code promptly.
When it happens
Trigger: elements[0] exists but lacks a usable title field (missing, null, or whitespace-only el.title, or el.title.text empty), e.g. restricted/placeholder course entries or an API payload-shape change.
Common situations: LinkedIn returning partial/teaser course data for region-locked courses; API schema change moving the title to a nested localized object; a draft/unpublished course matched by stale search indexes.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- LinkedIn Learning courses lookup returned malformed payload:
- Barchart greeks returned an unreadable options payload${data
- coingecko returned malformed JSON: ${error?.message || error
- coingecko global returned no data envelope
- coingecko returned an unexpected response
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/849a3c0320dfdc98.
Report an issue: GitHub.