jackwener/OpenCLI · error · CommandExecutionError

LinkedIn Learning feedRecommendationGroups returned malforme

Error message

LinkedIn Learning feedRecommendationGroups returned malformed payload: missing elements array

What it means

Thrown when feedRecommendationGroups returns JSON that does not contain a top-level 'elements' array. The trending logic iterates groups from result.json.elements; any other shape (RestLi error envelope, wrapper object, changed schema) is rejected as malformed before parsing to avoid undefined iteration.

Source

Thrown at clis/linkedin-learning/trending.js:50

    domain: DOMAIN,
    strategy: Strategy.COOKIE,
    browser: true,
    args: [
        { name: 'limit', type: 'int', default: 10, help: `Maximum results to return (1-${MAX_LIMIT})` },
    ],
    columns: ['rank', 'group', 'type', 'title', 'difficulty', 'viewers', 'url'],
    func: async (page, args) => {
        if (!page) throw new CommandExecutionError('Browser session required for linkedin-learning trending');
        const limit = parseLimit(args.limit);

        const url = `https://www.linkedin.com/learning-api/feedRecommendationGroups?countPerCarousel=${MAX_PER_CAROUSEL}&q=learner`;
        const result = await fetchLinkedInLearningApi(page, url);
        if (!result?.json) {
            throw new CommandExecutionError(`LinkedIn Learning feedRecommendationGroups failed: ${result?.error ?? 'no payload'}`);
        }
        const groups = result.json?.elements;
        if (!Array.isArray(groups)) {
            throw new CommandExecutionError('LinkedIn Learning feedRecommendationGroups returned malformed payload: missing elements array');
        }
        const rows = [];
        const seen = new Set();
        let rank = 1;
        let sawCards = false;
        for (const group of groups) {
            const carousels = Array.isArray(group?.carousels) ? group.carousels : [];
            for (const carousel of carousels) {
                const cards = Array.isArray(carousel?.cards) ? carousel.cards : [];
                for (const card of cards) {
                    sawCards = true;
                    if (rows.length >= limit) break;
                    const slug = card?.slug;
                    if (!slug || seen.has(slug)) continue;
                    seen.add(slug);
                    const row = parseCard(card, carousel, rank);
                    if (!row) continue;
                    rows.push(row);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log Object.keys(result.json) to see the actual payload structure.
  2. Update the CLI to a version matching the current feedRecommendationGroups schema.
  3. Add a fallback to unwrap alternate shapes (result.json.data?.elements or included arrays).
  4. Verify trending carousels still render on the LinkedIn Learning web page (indicates an API change, not local state).

Example fix

// before
const groups = result.json?.elements;
// after
const groups = result.json?.elements ?? result.json?.data?.elements;
if (!Array.isArray(groups)) throw new CommandExecutionError('malformed payload: keys=' + Object.keys(result.json ?? {}).join(','));
Defensive patterns

Strategy: type-guard

Validate before calling

// validate the groups payload before iterating
const json = result?.json;
if (!json || !Array.isArray(json.elements)) {
  throw new Error('Unexpected feedRecommendationGroups payload: ' + JSON.stringify(json)?.slice(0, 200));
}

Type guard

function isFeedGroupsPayload(json) {
  return !!json && typeof json === 'object' && Array.isArray(json.elements) &&
    json.elements.every(g => g && typeof g === 'object');
}

Try / catch

try {
  const rows = await trending(page);
} catch (e) {
  if (e.message.includes('malformed payload')) {
    console.error('feedRecommendationGroups schema changed; inspect payload keys and update CLI');
  } else throw e;
}

Prevention

When it happens

Trigger: result.json exists but result.json.elements is not an Array — e.g. a RestLi error object with HTTP 200, a payload wrapped in data/included keys, or LinkedIn changing the feedRecommendationGroups response schema.

Common situations: LinkedIn A/B-testing a new feed payload shape, endpoint deprecation/schema drift breaking an older CLI version, or an error envelope returned with a 200 status.

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/86fff4d7e49b37d7. Report an issue: GitHub.