jackwener/OpenCLI · error · CommandExecutionError

${webHost} feed: unexpected evaluate response

Error message

${webHost} feed: unexpected evaluate response

What it means

runFeed evaluates FEEDS_READ_JS in the page and requires the result to be a non-null object. If unwrapEvaluateResult returns null/primitive, it throws CommandExecutionError 'unexpected evaluate response'. This guards against the in-page script failing to return the expected hydration object.

Source

Thrown at clis/xiaohongshu/feed.js:105

        return url.toString();
    url.searchParams.set('xsec_token', cleanToken);
    url.searchParams.set('xsec_source', '');
    return url.toString();
}

/**
 * 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`);
        }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Reload https://<webHost>/explore and retry after the page fully renders
  2. Verify you are logged in and not redirected to a login or captcha page
  3. Increase the wait time after goto before evaluating (SPA may need longer than 2s)
  4. Open DevTools on /explore and run the same script to see what the store returns
  5. Check for site updates that changed the Pinia store structure and update FEEDS_READ_JS

Example fix

// before
await page.wait({ time: 2 });
const data = unwrapEvaluateResult(await page.evaluate(FEEDS_READ_JS));
// after
await page.wait({ time: 5 }); // longer hydration window
await page.waitForSelector('.note-item'); // ensure feed rendered
const data = unwrapEvaluateResult(await page.evaluate(FEEDS_READ_JS));
Defensive patterns

Strategy: retry

Validate before calling

// ensure page is on explore and rendered before evaluating
if (!page.url().includes('/explore')) await page.goto(`https://${webHost}/explore`);
await page.waitForSelector('.note-item');

Type guard

function isFeedPayload(d) { return !!d && typeof d === 'object'; }

Try / catch

try {
  const data = unwrapEvaluateResult(await page.evaluate(FEEDS_READ_JS));
} catch (err) {
  if (err instanceof CommandExecutionError && err.message.includes('unexpected evaluate response')) {
    await page.reload(); await page.wait({ time: 5 }); // retry once
  } else throw err;
}

Prevention

When it happens

Trigger: page.evaluate(FEEDS_READ_JS) resolves to undefined/null or a non-object after page.goto(https://<webHost>/explore) and a 2-second wait.

Common situations: The SPA failed to boot (JS error on page), redirect to a login/captcha page where the expected global store does not exist, network issues leaving /explore blank, or site changes removing the store the script reads.

Related errors


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