jackwener/OpenCLI · error · CommandExecutionError

${webHost} feed: malformed feed item

Error message

${webHost} feed: malformed feed item

What it means

Each entry in data.items must be a non-null object. runFeed throws 'malformed feed item' when a row is null, undefined, or a primitive. This is a per-item integrity check while building the result rows.

Source

Thrown at clis/xiaohongshu/feed.js:118

    // Pinia store hydrates from SSR; give the page a beat to finish
    // bootstrapping before reading the array.
    await page.wait({ time: 2 });
    const data = unwrapEvaluateResult(await page.evaluate(FEEDS_READ_JS));
    if (!data || typeof data !== 'object') {
        throw new CommandExecutionError(`${webHost} feed: unexpected evaluate response`);
    }
    if (data.error) {
        throw new CommandExecutionError(`${webHost} feed: ${data.error}`, `The SPA may still be hydrating; reload ${webHost}/explore and retry.`);
    }
    if (!Array.isArray(data.items)) {
        throw new CommandExecutionError(`${webHost} feed: unexpected items payload shape`);
    }
    const rows = [];
    for (const row of data.items) {
        if (rows.length >= limit)
            break;
        if (!row || typeof row !== 'object') {
            throw new CommandExecutionError(`${webHost} feed: malformed feed item`);
        }
        const id = toCleanString(row.id);
        if (!id) {
            throw new CommandExecutionError(`${webHost} feed: feed item is missing note id`);
        }
        const xsecToken = toCleanString(row.xsecToken);
        if (!xsecToken) {
            throw new CommandExecutionError(`${webHost} feed: feed item ${id} is missing xsecToken; cannot build a signed drill-down URL`);
        }
        rows.push({
            id,
            title: toCleanString(row.title),
            type: toCleanString(row.type),
            author: toCleanString(row.author),
            likes: toCleanString(row.likes),
            url: buildFeedNoteUrl(webHost, id, xsecToken),
        });
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Filter out non-object rows before parsing instead of failing the whole command
  2. Update FEEDS_READ_JS to normalize items to objects
  3. Retry after full hydration; placeholder rows often disappear once loaded
  4. Log data.items to identify which entries are malformed

Example fix

// before
for (const row of data.items) {
    if (!row || typeof row !== 'object') {
        throw new CommandExecutionError(`${webHost} feed: malformed feed item`);
    }
// after
for (const row of data.items.filter(r => r && typeof r === 'object')) {
    // skip malformed rows instead of aborting
Defensive patterns

Strategy: type-guard

Validate before calling

const cleanItems = (data.items ?? []).filter(r => r && typeof r === 'object');

Type guard

function isFeedItem(row) { return !!row && typeof row === 'object' && !Array.isArray(row); }

Try / catch

try {
  const rows = await runFeed(page, webHost, limit);
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.includes('malformed feed item')) {
    // filter/skip bad rows or refresh the page and retry
  } else throw err;
}

Prevention

When it happens

Trigger: data.items contains null/undefined entries or primitive values (strings/numbers) instead of note objects.

Common situations: Site inserts placeholder/ad entries as null, partial SSR hydration leaving holes in the items array, site schema change where items are keyed objects rather than an array of objects.

Understand the failure class

Related errors


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