jackwener/OpenCLI · error · CommandExecutionError

${webHost} feed: unexpected items payload shape

Error message

${webHost} feed: unexpected items payload shape

What it means

runFeed requires data.items to be an array. If the hydrated object exists but items is missing or not an array, it throws CommandExecutionError 'unexpected items payload shape'. This validates the feed store schema the CLI depends on.

Source

Thrown at clis/xiaohongshu/feed.js:111

/**
 * Shared func-mode implementation. Exported so the rednote adapter can run the
 * same store read against www.rednote.com without duplicating the logic.
 */
export async function runFeed(page, kwargs, webHost) {
    const limit = parseLimit(kwargs.limit);
    await page.goto(`https://${webHost}/explore`);
    // 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,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the store in DevTools to confirm the current items property name/path
  2. Update FEEDS_READ_JS to read the new store path
  3. Retry when the page has fully hydrated so items is populated
  4. Fall back to another feed/tab if the explore feed shape differs

Example fix

// before (in-page script)
return { items: store.feed.notes };
// after (tolerate alternate shapes)
const raw = store.feed?.notes ?? store.feed?.items ?? [];
return { items: Array.isArray(raw) ? raw : [] };
Defensive patterns

Strategy: type-guard

Validate before calling

const data = unwrapEvaluateResult(await page.evaluate(FEEDS_READ_JS));
if (!data || !Array.isArray(data.items)) throw new Error('feed items payload malformed');

Type guard

function hasFeedItems(d) { return !!d && typeof d === 'object' && Array.isArray(d.items); }

Try / catch

try {
  const rows = await runFeed(page, webHost, limit);
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.includes('unexpected items payload shape')) {
    // inspect raw store in DevTools; update FEEDS_READ_JS to the new items path
  } else throw err;
}

Prevention

When it happens

Trigger: page.evaluate(FEEDS_READ_JS) returns an object without an items array, e.g. items is undefined, an object map, or a wrapped { list: [...] } structure after a site update.

Common situations: Xiaohongshu changed their Pinia store shape (renamed/moved items), explore page rendered an empty/error state whose store lacks items, custom feed types with different payloads.

Related errors


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