jackwener/OpenCLI · error · CommandExecutionError

Malformed Xiaohongshu user snapshot: notes array was not fou

Error message

Malformed Xiaohongshu user snapshot: notes array was not found

What it means

The snapshot had a readable user store but its notes data was missing: notesPresent was not true or noteGroups was not an array. The xiaohongshu user store keeps notes as [tab[], tab[], ...] groups; if that structure is absent the profile's note data never loaded. Downstream note-count/scroll logic depends on it.

Source

Thrown at clis/xiaohongshu/user.js:49

        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) {
    return Boolean(snapshot && typeof snapshot === 'object' && snapshot.loginWall === true);
}
function throwLoginWallAuthRequired() {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry — notes may just be slow to hydrate; wait for the notes group to appear before snapshotting
  2. Check whether the profile genuinely has no public notes (in which case the command will next throw EmptyResultError)
  3. Inspect the live store shape in devtools and update USER_SNAPSHOT_JS/notesPresent detection after site schema changes
  4. Try a different profile to distinguish per-user empty state from a broken selector
Defensive patterns

Strategy: retry

Validate before calling

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

Type guard

function hasNotes(s) { return Boolean(s && typeof s === 'object' && s.notesPresent === true && Array.isArray(s.noteGroups)); }

Try / catch

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

Prevention

When it happens

Trigger: The notes arrays had not hydrated yet when the snapshot was taken; the user profile page variant renders notes differently (e.g. empty state, suspended account); site changed the store shape so notesPresent check no longer matches.

Common situations: Profiles whose notes lazy-load only after scrolling; users with zero public notes; site-side schema update renaming the notes field.

Understand the failure class

Related errors


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