jackwener/OpenCLI · error · CommandExecutionError

Malformed Xiaohongshu user snapshot: user store was not foun

Error message

Malformed Xiaohongshu user snapshot: user store was not found

What it means

The snapshot came back as an object but its storePresent flag was not true, meaning USER_SNAPSHOT_JS could not find the user store (e.g. __INITIAL_STATE__.user) on the page. This is a known hydration race: the store is injected asynchronously by SSR/client bootstrap after page.goto, so evaluating too early intermittently fails (documented in the source as the 2026-06-09 bug fixed by adding page.wait).

Source

Thrown at clis/xiaohongshu/user.js:46

      return {
        noteGroups: safeClone(rawNotes || []),
        pageData: safeClone(rawPageData || {}),
        storePresent: hasUserStore,
        notesPresent: Array.isArray(rawNotes),
        pageDataPresent: Boolean(rawPageData && typeof rawPageData === 'object' && Object.keys(rawPageData).length > 0),
        loginWall: Boolean(onLoginPage || loggedInVal === false),
      };
    })()
  `;
async function readUserSnapshot(page) {
    return await page.evaluate(USER_SNAPSHOT_JS);
}
export function assertReadableUserSnapshot(snapshot) {
    if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) {
        throw new CommandExecutionError('Malformed Xiaohongshu user snapshot');
    }
    if (snapshot.storePresent !== true) {
        throw new CommandExecutionError('Malformed Xiaohongshu user snapshot: user store was not found');
    }
    if (snapshot.notesPresent !== true || !Array.isArray(snapshot.noteGroups)) {
        throw new CommandExecutionError('Malformed Xiaohongshu user snapshot: notes array was not found');
    }
}
/** 展平 noteGroups 后的真实笔记条数。小红书 user store 的 notes 是 [tab[], tab[], ...]
 *  形态(每个 tab 一个数组),首屏笔记在其中某个 tab 里;这里数所有 tab 里的笔记总数。 */
export function countFlatNotes(snapshot) {
    const groups = snapshot?.noteGroups;
    if (!Array.isArray(groups))
        return 0;
    let n = 0;
    for (const g of groups)
        n += Array.isArray(g) ? g.length : (g ? 1 : 0);
    return n;
}
/** 页面是否被登录墙挡(302 到 /login,或 user store loggedIn=false)。 */
export function isLoginWallSnapshot(snapshot) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command — the comment in user.js says hydration waits + retries were added precisely for this intermittent race
  2. Wait for the store before evaluating (waitForSelector or wait-for-function on __INITIAL_STATE__.user)
  3. Check for a login wall: if the page redirected to /login the store will never appear — re-authenticate instead of retrying
  4. Slow network: increase the hydration wait duration

Example fix

// before
const snapshot = await readUserSnapshot(page);
// after
await page.waitForFunction(() => window.__INITIAL_STATE__?.user, { timeout: 15000 });
const snapshot = await readUserSnapshot(page);
Defensive patterns

Strategy: retry

Validate before calling

await page.waitForFunction(() => Boolean(window.__INITIAL_STATE__?.user), { timeout: 15000 });

Type guard

function hasUserStore(s) { return Boolean(s && typeof s === 'object' && s.storePresent === true); }

Try / catch

try {
  await getUserProfile(url);
} catch (err) {
  if (/user store was not found/.test(err.message)) {
    await sleep(3000); await retryWithBackoff(() => getUserProfile(url), 3);
  } else throw err;
}

Prevention

When it happens

Trigger: Evaluating USER_SNAPSHOT_JS immediately after page.goto before the client bootstrap injects __INITIAL_STATE__.user; landing on a page variant without the user store; login-walled or error page lacking app state.

Common situations: Slow network/CPU on first load; cold page with no cache; fetching a user profile right after navigation in a fresh browser context.

Understand the failure class

Related errors


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