{"record":{"id":"68d24bba0d680916","repo":"DIYgod/RSSHub","slug":"json-stringify-userpagedata-re","errorCode":null,"errorMessage":"小红书未返回用户数据，请稍后再试: ${JSON.stringify(userPageData.result)}","messagePattern":"小红书未返回用户数据，请稍后再试: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"error","filePath":"lib/routes/xiaohongshu/util.ts","lineNumber":115,"sourceCode":"                        const response = await page.waitForResponse(\n                            (res) => {\n                                const req = res.request();\n                                return req.url().includes('/api/sns/web/v2/note/collect/page') && req.method() === 'GET' && req.resourceType() === 'xhr';\n                            },\n                            { timeout: 5000 }\n                        );\n                        collect = await response.json();\n                    } catch {\n                        //\n                    }\n                }\n\n                let { userPageData, notes } = initialState.user;\n                userPageData = userPageData._rawValue || userPageData;\n                notes = notes._rawValue || notes;\n\n                if (!userPageData.basicInfo) {\n                    throw new Error(`小红书未返回用户数据，请稍后再试: ${JSON.stringify(userPageData.result)}`);\n                }\n\n                return { userPageData, notes, collect };\n            } finally {\n                await destroy();\n            }\n        },\n        config.cache.routeExpire,\n        false\n    );\n\nconst getBoard = (url, cache) =>\n    cache.tryGet(\n        url,\n        async () => {\n            // Use proxy if configured\n            if (config.xiaohongshu.proxy) {\n                const res = await fetchWithProxy(url);","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/xiaohongshu/util.ts#L97-L133","documentation":"Thrown by getUser in the Xiaohongshu (小红书) route after Playwright loads a user profile page and parses window.__INITIAL_STATE__. The code expects initialState.user.userPageData to carry a basicInfo object; when that field is absent the user payload is considered invalid and the route aborts, embedding userPageData.result in the message for diagnostics. It is a raw Error (not a typed RSSHub error), so the message text is the only discriminator.","triggerScenarios":"Playwright navigates to an xiaohongshu.com user page, the page passes the captcha/lock-icon check, extractInitialState succeeds, but initialState.user.userPageData has no basicInfo property (e.g. userPageData is {} or only carries a redirect/error result). Happens when the user_id does not exist, the account was banned/private, XHS returned a login-required or risk-control interstitial that still rendered __INITIAL_STATE__, or the configured cookie expired so XHS omitted the user section.","commonSituations":"Cookie (XIAOHONGSHU_COOKIE) not set or expired; a stale/incorrect user id in the route path; XHS tightened anti-bot and returns a partial state instead of the captcha box that line 87 checks; XHS shipped a page redesign renaming basicInfo.","solutions":["Set or refresh XIAOHONGSHU_COOKIE in the instance config with a freshly logged-in browser cookie and retry.","Open the same user URL in a browser to confirm the account exists and is public; if XHS shows a login wall, the cookie is the cause.","Retry after a few minutes — XHS risk-control often throttles temporarily and recovers.","If persistent, inspect the embedded JSON.stringify(userPageData.result) in the message to see whether XHS changed the payload shape, then update the basicInfo check in lib/routes/xiaohongshu/util.ts:114.","Run behind a proxy (config.xiaohongshu.proxy) if the deploy IP is geo-blocked or rate-limited by XHS."],"exampleFix":"// before\nif (!userPageData.basicInfo) {\n    throw new Error(`小红书未返回用户数据，请稍后再试: ${JSON.stringify(userPageData.result)}`);\n}\n\n// after — surface the anti-bot/login causes distinctly and keep the raw payload for debugging\nif (!userPageData?.basicInfo) {\n    const hint = userPageData?.result ? `小红书返回异常: ${JSON.stringify(userPageData.result)}` : '小红书未返回用户数据，可能是 Cookie 过期或账号不存在';\n    throw new Error(hint);\n}","handlingStrategy":"retry","validationCode":"// Before calling getUser, confirm the user id looks like an XHS id and the cookie is set\nimport { config } from '@/config';\nfunction preflightXhsUser(userId: string) {\n    if (!userId || /[\\\\/?#]/.test(userId)) {\n        throw new Error(`Suspicious XHS user id: ${userId}`);\n    }\n    if (!config.xiaohongshu.cookie) {\n        throw new Error('XIAOHONGSHU_COOKIE is not set; getUser will likely fail with missing basicInfo');\n    }\n}","typeGuard":"function hasBasicInfo(userPageData: unknown): userPageData is { basicInfo: Record<string, unknown> } {\n    return typeof userPageData === 'object' && userPageData !== null && 'basicInfo' in userPageData && typeof (userPageData as any).basicInfo === 'object';\n}","tryCatchPattern":"// XHS risk-control is transient — retry a couple of times before surfacing\nlet lastErr;\nfor (let attempt = 0; attempt < 3; attempt++) {\n    try {\n        return await getUser(url, cache);\n    } catch (e) {\n        lastErr = e;\n        if (!/未返回用户数据/.test(e.message)) throw e;\n        await new Promise((r) => setTimeout(r, (attempt + 1) * 2000));\n    }\n}\nthrow lastErr;","preventionTips":["Keep XIAOHONGSHU_COOKIE fresh — XHS sessions expire and risk-control kicks in without one.","Confirm the user account is public and exists before subscribing.","Cache getUser results (the route already uses cache.tryGet) to reduce XHS request volume and avoid tripping anti-bot.","Run behind config.xiaohongshu.proxy if the deploy IP is flagged."],"tags":["xiaohongshu","scraping","anti-bot","cookie","playwright"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}