jackwener/OpenCLI · error · CommandExecutionError

LinkedIn Learning courses lookup returned malformed payload:

Error message

LinkedIn Learning courses lookup returned malformed payload: missing elements array

What it means

The learning-api returned JSON, but result.json.elements is not an array. The /learning-api/courses endpoint is expected to return { elements: [...] }; anything else (an error object, a JSON auth response, a changed schema) is treated as a malformed payload and rejected with this CommandExecutionError.

Source

Thrown at clis/linkedin-learning/course.js:81

    domain: DOMAIN,
    strategy: Strategy.COOKIE,
    browser: true,
    args: [
        { name: 'slug', type: 'string', required: true, positional: true, help: 'Course slug (e.g. agentic-ai-build-your-first-agentic-ai-system) or full /learning/<slug> URL' },
    ],
    columns: ['title', 'slug', 'description', 'difficulty', 'duration_sec', 'videos_count', 'rating', 'rating_count', 'released', 'url'],
    func: async (page, args) => {
        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

  1. Re-authenticate the browser session (expired cookies often produce non-course JSON) and retry.
  2. Log the raw result.json to inspect the actual payload shape and confirm the API response schema.
  3. Check for LinkedIn learning-api schema/auth changes; update the library if the elements key moved.
  4. Retry later if it's a transient API-side issue; use search to cross-check that the service works.
Defensive patterns

Strategy: type-guard

Validate before calling

const res = await fetchLinkedInLearningApi(page, apiUrl);
if (res?.json && !Array.isArray(res.json?.elements)) {
  console.warn('Unexpected learning-api payload:', res.json);
}

Type guard

function hasElements(json) {
  return json != null && typeof json === 'object' && Array.isArray(json.elements);
}

Try / catch

try {
  await runCommand('linkedin-learning', 'course', [slug]);
} catch (e) {
  if (e.message.includes('missing elements array')) {
    await refreshSession(); // or inspect raw payload for schema change
  } else throw e;
}

Prevention

When it happens

Trigger: The endpoint responds with valid JSON that lacks an elements array — e.g. an error/status JSON body, a login-related JSON response, or a LinkedIn API schema change where results moved to a different key.

Common situations: Session expired but server returned a JSON error envelope; LinkedIn rolled out an API version change; an intermediate proxy replaced the body with its own JSON error.

Understand the failure class

Related errors


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