{"record":{"id":"6280183211c7a0e7","repo":"jackwener/OpenCLI","slug":"xiaohongshu-profile-requires-login-page-redirecte","errorCode":null,"errorMessage":"Xiaohongshu profile requires login (page redirected to /login or session expired); re-login to xiaohongshu.com and retry.","messagePattern":"Xiaohongshu profile requires login \\(page redirected to /login or session expired\\); re-login to xiaohongshu\\.com and retry\\.","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/user.js","lineNumber":68,"sourceCode":"    }\n}\n/** 展平 noteGroups 后的真实笔记条数。小红书 user store 的 notes 是 [tab[], tab[], ...]\n *  形态（每个 tab 一个数组），首屏笔记在其中某个 tab 里；这里数所有 tab 里的笔记总数。 */\nexport function countFlatNotes(snapshot) {\n    const groups = snapshot?.noteGroups;\n    if (!Array.isArray(groups))\n        return 0;\n    let n = 0;\n    for (const g of groups)\n        n += Array.isArray(g) ? g.length : (g ? 1 : 0);\n    return n;\n}\n/** 页面是否被登录墙挡（302 到 /login，或 user store loggedIn=false）。 */\nexport function isLoginWallSnapshot(snapshot) {\n    return Boolean(snapshot && typeof snapshot === 'object' && snapshot.loginWall === true);\n}\nfunction throwLoginWallAuthRequired() {\n    throw new AuthRequiredError('xiaohongshu.com', 'Xiaohongshu profile requires login (page redirected to /login or session expired); re-login to xiaohongshu.com and retry.');\n}\n/**\n * 读取 user 快照，带 hydration 等待 + 重试。修两个真实坑：\n *  1) 慢加载竞态：`__INITIAL_STATE__.user` 由 SSR/client bootstrap 异步注入，`page.goto` 后\n *     立刻 evaluate 会撞 hydration 窗口 → store/notes 尚未就绪。note.js / download.js 早用\n *     `page.wait` 规避，唯独 user.js 漏了 → 间歇性 \"user store was not found\"（2026-06-09 整批\n *     seed 全挂、2026-05-20 亦复现）。\n *  2) 笔记懒加载：`notes` 是 [tab[], ...] 形态，首屏笔记可能比 store 更晚填充。\n * 策略：先快读一次（页面已就绪则零额外延迟，保住快加载路径）；未拿到笔记**且非登录墙**就\n * `page.wait` 后重试至多 maxRetries 次。命中登录墙立即停（再等无用，交给 caller 抛 AUTH_REQUIRED）；\n * 真·空号（销号/私密/全删）走满重试后返回空快照，由下游 EmptyResultError 正确收尾。导出供测试。\n */\nexport async function readUserSnapshotHydrated(page, maxRetries = 8, waitSeconds = 2) {\n    let snapshot = await readUserSnapshot(page);\n    for (let i = 0; i < maxRetries && !isLoginWallSnapshot(snapshot) && countFlatNotes(snapshot) === 0; i += 1) {\n        await page.wait({ time: waitSeconds });\n        snapshot = await readUserSnapshot(page);\n    }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/user.js#L50-L86","documentation":"The profile page hit a login wall: the snapshot's loginWall flag was true (page redirected to /login or the user store reported loggedIn=false), so throwLoginWallAuthRequired throws AuthRequiredError for xiaohongshu.com. The library treats this as an authentication problem, not a fetch failure — the session cookie is expired or missing.","triggerScenarios":"Session cookies expired since last login; the profile fetch triggered a 302 to /login; the page's user store explicitly reports loggedIn=false; cookies were cleared or the browser profile was reset.","commonSituations":"Long-running automation whose xiaohongshu session aged out; running on a machine/browser context that was never logged in; site forcing re-login due to suspicious activity.","solutions":["Re-login to xiaohongshu.com in the browser context used by the CLI (refresh cookies), then retry the command","Use the library's auth/login flow for xiaohongshu if available to refresh credentials","Verify cookies persist across runs (same user-data-dir) instead of a fresh context each time","Check the target profile in a normal browser to confirm it isn't actually a public redirect to /login"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"import { AuthRequiredError } from '...';\ntry {\n  await getUserProfile(url);\n} catch (err) {\n  if (err instanceof AuthRequiredError) {\n    await reloginXiaohongshu(); // refresh cookies, then retry once\n    return getUserProfile(url);\n  }\n  throw err;\n}","preventionTips":["Refresh the xiaohongshu.com session proactively before long crawl runs","Use a persistent browser profile so cookies survive restarts","Detect /login redirects early and stop instead of hammering retry"],"tags":["authentication","login-wall","session-expired","xiaohongshu"],"backgroundTag":"login-wall-auth-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}