xpzouying/xiaohongshu-mcp · error

check login status failed

Error message

check login status failed

What it means

CheckLoginStatus navigates the go-rod page to xiaohongshu.com/explore and queries the login-state CSS selector via pp.Has. This error wraps a failure of the Has query itself — a rod/CDP protocol error, page crash, navigation/context timeout, or target closed — as opposed to merely the element being absent. It means the check could not be performed, not that the user is logged out.

Source

Thrown at xiaohongshu/login.go:29

type LoginAction struct {
	page *rod.Page
}

func NewLogin(page *rod.Page) *LoginAction {
	return &LoginAction{page: page}
}

func (a *LoginAction) CheckLoginStatus(ctx context.Context) (bool, error) {
	// 加超时保护:只是查登录态的快速检查,不应无限挂(登录扫码的等待在 Login/WaitForLogin 里)
	pp := a.page.Context(ctx).Timeout(30 * time.Second)
	pp.MustNavigate("https://www.xiaohongshu.com/explore").MustWaitLoad()

	time.Sleep(1 * time.Second)

	exists, _, err := pp.Has(`.main-container .user .link-wrapper .channel`)
	if err != nil {
		return false, errors.Wrap(err, "check login status failed")
	}

	if !exists {
		return false, errors.Wrap(err, "login status element not found")
	}

	return true, nil
}

// CurrentUser 当前登录用户的基础信息。
type CurrentUser struct {
	Nickname string `json:"nickname"`
	UserID   string `json:"userId"`
}

// CurrentUser 从当前页面的 __INITIAL_STATE__ 读取登录用户信息。
// 需在 CheckLoginStatus 之后调用:复用已加载的 explore 页,不做额外导航。
func (a *LoginAction) CurrentUser(ctx context.Context) (*CurrentUser, error) {

View on GitHub (pinned to 332d196854)

Solutions

  1. Check the wrapped err for context.DeadlineExceeded / 'target closed' and re-create the page/browser if the target is gone
  2. Increase the timeout or verify the ctx passed in has enough budget for navigate + load + 1s sleep + query
  3. Confirm the browser process is alive and the rod page still valid before calling; retry the check once after re-navigating
  4. Test network access to https://www.xiaohongshu.com/explore from the host

Example fix

// before
exists, _, err := pp.Has(`.main-container .user .link-wrapper .channel`)
if err != nil {
	return false, errors.Wrap(err, "check login status failed")
}
// after
exists, _, err := pp.Has(`.main-container .user .link-wrapper .channel`)
if err != nil {
	if errors.Is(ctx.Err(), context.DeadlineExceeded) {
		return false, errors.Wrap(err, "check login status timed out")
	}
	return false, errors.Wrap(err, "check login status failed")
}
Defensive patterns

Strategy: retry

Validate before calling

// 调用前确认浏览器与页面仍可用
if page == nil {
	return errors.New("page is nil")
}
if _, err := page.Context(ctx).Timeout(3 * time.Second).Eval(`() => document.readyState`); err != nil {
	return fmt.Errorf("browser page not alive: %w", err)
}

Type guard

func isTimeoutErr(err error) bool {
	return errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "timeout") || strings.Contains(err.Error(), "target closed")
}

Try / catch

loggedIn, err := loginAction.CheckLoginStatus(ctx)
if err != nil {
	if isTimeoutErr(err) {
		// 浏览器/网络抖动:重建页面后重试一次
		page = browser.MustPage("https://www.xiaohongshu.com")
		loggedIn, err = loginAction.CheckLoginStatus(ctx)
	}
	if err != nil {
		return fmt.Errorf("login check failed: %w", err)
	}
}

Prevention

When it happens

Trigger: Calling CheckLoginStatus when: the passed ctx is already expired or times out within the 30s window; the browser/tab was closed between navigation and query; page navigation failed (MustNavigate panics aside, the DOM query races a crashed renderer); rod's WebSocket connection to the browser dropped.

Common situations: Slow network so explore page load exceeds the 30s Timeout; headless browser killed by OOM; caller cancelled the context; xiaohongshu.com unreachable or returning an error page that breaks the expected DOM query.

Related errors


AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05). Data as JSON: /api/errors/0dbbc870a43046ed. Report an issue: GitHub.