{"record":{"id":"1d657990be2b0aeb","repo":"xpzouying/xiaohongshu-mcp","slug":"login-status-element-not-found","errorCode":null,"errorMessage":"login status element not found","messagePattern":"login status element not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"xiaohongshu/login.go","lineNumber":33,"sourceCode":"\nfunc NewLogin(page *rod.Page) *LoginAction {\n\treturn &LoginAction{page: page}\n}\n\nfunc (a *LoginAction) CheckLoginStatus(ctx context.Context) (bool, error) {\n\t// 加超时保护：只是查登录态的快速检查，不应无限挂（登录扫码的等待在 Login/WaitForLogin 里）\n\tpp := a.page.Context(ctx).Timeout(30 * time.Second)\n\tpp.MustNavigate(\"https://www.xiaohongshu.com/explore\").MustWaitLoad()\n\n\ttime.Sleep(1 * time.Second)\n\n\texists, _, err := pp.Has(`.main-container .user .link-wrapper .channel`)\n\tif err != nil {\n\t\treturn false, errors.Wrap(err, \"check login status failed\")\n\t}\n\n\tif !exists {\n\t\treturn false, errors.Wrap(err, \"login status element not found\")\n\t}\n\n\treturn true, nil\n}\n\n// CurrentUser 当前登录用户的基础信息。\ntype CurrentUser struct {\n\tNickname string `json:\"nickname\"`\n\tUserID   string `json:\"userId\"`\n}\n\n// CurrentUser 从当前页面的 __INITIAL_STATE__ 读取登录用户信息。\n// 需在 CheckLoginStatus 之后调用：复用已加载的 explore 页，不做额外导航。\nfunc (a *LoginAction) CurrentUser(ctx context.Context) (*CurrentUser, error) {\n\tpp := a.page.Context(ctx).Timeout(10 * time.Second)\n\n\tres, err := pp.Eval(`() => {\n\t\tconst u = window.__INITIAL_STATE__ && window.__INITIAL_STATE__.user;","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/login.go#L15-L51","documentation":"CheckLoginStatus concludes the user is NOT logged in when the `.main-container .user .link-wrapper .channel` element is absent from the explore page, and returns this error. Note the bug: errors.Wrap(err, ...) is called with err == nil here, so the resulting error is effectively errors.New(\"login status element not found\"). It conflates 'definitely logged out' with 'page rendered differently than expected'.","triggerScenarios":"Calling CheckLoginStatus when: the session cookie expired so the page shows the logged-out layout; Xiaohongshu changed/expired the DOM class names (A/B tests, redesign); the 1-second sleep was not enough and the user menu hadn't rendered yet; a lightweight/anti-bot page variant rendered without the .main-container structure.","commonSituations":"Long-lived sessions expiring overnight; site frontend update renaming .link-wrapper/.channel classes; headless fingerprint flagged and served a degraded page; slow render where the element appears after the query but the library doesn't wait for it.","solutions":["Manually open the explore page in the same browser profile and inspect whether the selector still exists; update the CSS selector if the DOM changed","Replace the fixed time.Sleep with rod's Wait/WaitRequestIdle or retry Has a few times before concluding logged-out","Re-run the Login flow to refresh cookies, then call CheckLoginStatus again","Return a typed 'not logged in' sentinel instead of relying on the wrapped (nil) error, and use errors.Is in callers"],"exampleFix":"// before\nif !exists {\n\treturn false, errors.Wrap(err, \"login status element not found\")\n}\n// after\nif !exists {\n\t// 再等待重试一次，排除慢渲染导致的误判\n\tpp.WaitStable(500 * time.Millisecond)\n\tif exists2, _, _ := pp.Has(`.main-container .user .link-wrapper .channel`); !exists2 {\n\t\treturn false, errors.New(\"login status element not found (likely logged out)\")\n\t}\n}","handlingStrategy":"fallback","validationCode":"// 调用前先确认有会话 cookie\ncookies, _ := page.Cookies(\"https://www.xiaohongshu.com\")\nhasSession := false\nfor _, c := range cookies {\n\tif c.Name == \"web_session\" && c.Value != \"\" {\n\t\thasSession = true\n\t}\n}\nif !hasSession {\n\treturn errors.New(\"no session cookie, login required\")\n}","typeGuard":"func isNotLoggedInErr(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"login status element not found\")\n}","tryCatchPattern":"loggedIn, err := loginAction.CheckLoginStatus(ctx)\nif err != nil {\n\tif isNotLoggedInErr(err) {\n\t\t// 回退：走完整登录流程后重查\n\t\tif err := loginAction.Login(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tloggedIn, err = loginAction.CheckLoginStatus(ctx)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n}\n_ = loggedIn","preventionTips":["Refresh session cookies proactively before long automation runs","Prefer rod Wait/WaitStable over fixed time.Sleep before querying selectors","Re-verify CSS selectors after Xiaohongshu frontend updates","Treat 'element not found' as 'unknown state' and retry once before concluding logged-out"],"tags":["go","go-rod","css-selector","login-state","web-automation"],"backgroundTag":"dom-element-not-found","analyzedSha":"332d196854a9eac0d2b8c2c0e3d0cc43139d724c","analyzedAt":"2026-09-05T22:22:55.988Z","contentChangedAt":"2026-09-05T22:22:55.988Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}