{"record":{"id":"47d79e277e77becb","repo":"xpzouying/xiaohongshu-mcp","slug":"unmarshal-current-user-failed","errorCode":null,"errorMessage":"unmarshal current user failed","messagePattern":"unmarshal current user failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/login.go","lineNumber":67,"sourceCode":"\n\tres, err := pp.Eval(`() => {\n\t\tconst u = window.__INITIAL_STATE__ && window.__INITIAL_STATE__.user;\n\t\tconst info = u && u.userInfo && u.userInfo.value !== undefined ? u.userInfo.value : (u && u.userInfo);\n\t\tif (!info || info.guest) return \"\";\n\t\treturn JSON.stringify({nickname: info.nickname, userId: info.userId || info.user_id});\n\t}`)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"read current user state failed\")\n\t}\n\n\traw := res.Value.String()\n\tif raw == \"\" {\n\t\treturn nil, errors.New(\"current user not found in page state\")\n\t}\n\n\tvar user CurrentUser\n\tif err := json.Unmarshal([]byte(raw), &user); err != nil {\n\t\treturn nil, errors.Wrap(err, \"unmarshal current user failed\")\n\t}\n\n\treturn &user, nil\n}\n\nfunc (a *LoginAction) Login(ctx context.Context) error {\n\tpp := a.page.Context(ctx)\n\n\t// 导航到小红书首页，这会触发二维码弹窗\n\tpp.MustNavigate(\"https://www.xiaohongshu.com/explore\").MustWaitLoad()\n\n\ttime.Sleep(2 * time.Second)\n\n\tif exists, _, _ := pp.Has(\".main-container .user .link-wrapper .channel\"); exists {\n\t\treturn nil\n\t}\n\n\tpp.MustElement(\".main-container .user .link-wrapper .channel\")","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/login.go#L49-L85","documentation":"CurrentUser builds a JSON string inside the page (JSON.stringify of nickname/userId) and decodes it into the CurrentUser struct with json.Unmarshal. 'unmarshal current user failed' means the string returned by the page is not valid JSON or its shape doesn't satisfy the struct's expectations, so decoding into CurrentUser{Nickname,UserID} failed.","triggerScenarios":"The page's __INITIAL_STATE__ yields fields that are not strings (e.g. userId as a number is fine, but nested objects/arrays serialized differently will not match); a xiaohongshu front-end change makes the eval return a different structure (e.g. the whole info object instead of {nickname,userId}); locale/encoding issues corrupt the JSON string.","commonSituations":"Site redesign moving user info out of __INITIAL_STATE__.user.userInfo; the eval's fallback branch (u.userInfo without .value) returning an object with extra/non-JSON-compatible content; data races where the state updates mid-stringify.","solutions":["Log the raw value of res.Value.String() to see what the page actually returned","Compare it against the CurrentUser struct {nickname string, userId string} and update the eval JS or struct tags to match the new site shape","Make the eval stricter: build the object explicitly with String(info.nickname) and String(info.userId||info.user_id) so Unmarshal always receives strings","Pin/update the library version after checking whether xiaohongshu changed __INITIAL_STATE__ (this is a scraping-fragility error, not a caller bug)"],"exampleFix":"// before\nreturn JSON.stringify({nickname: info.nickname, userId: info.userId || info.user_id});\n// after\nreturn JSON.stringify({nickname: String(info.nickname ?? \"\"), userId: String(info.userId ?? info.user_id ?? \"\")});","handlingStrategy":"type-guard","validationCode":"raw := \"\"\n// decode defensively after reading page state\nvar probe map[string]any\nif err := json.Unmarshal([]byte(raw), &probe); err != nil { return nil, fmt.Errorf(\"page returned non-JSON: %q\", raw) }","typeGuard":"func looksLikeUserJSON(s string) bool {\n    var v struct {\n        Nickname string `json:\"nickname\"`\n        UserID   string `json:\"userId\"`\n    }\n    return json.Unmarshal([]byte(s), &v) == nil\n}","tryCatchPattern":"user, err := login.CurrentUser(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"unmarshal current user failed\") {\n        // site state shape changed; log raw payload and degrade gracefully\n        return nil, ErrUserParseUnavailable\n    }\n    return err\n}","preventionTips":["Log the raw JSON the page returns whenever unmarshal fails, to detect site redesigns early","Pin a known-good library version and check its issues before upgrading","Pin expectations in your own integration test: CurrentUser must return non-empty Nickname","Handle userId arriving as a number in the JSON by accepting json.Number in custom types"],"tags":["go","json","unmarshal","scraping","schema-change"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"332d196854a9eac0d2b8c2c0e3d0cc43139d724c","analyzedAt":"2026-09-05T22:22:55.988Z","contentChangedAt":"2026-09-05T22:22:55.988Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}