{"record":{"id":"2389c85385f40bff","repo":"siyuan-note/siyuan","slug":"invalid-user","errorCode":null,"errorMessage":"invalid user","messagePattern":"invalid user","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/cloud_service.go","lineNumber":699,"sourceCode":"\t\tdesc = audioRegexp.ReplaceAllString(desc, \" 语音 \")\n\t\tdesc = videoRegexp.ReplaceAllString(desc, \" 视频 \")\n\t\tdesc = fileRegexp.ReplaceAllString(desc, \" 文件 \")\n\t\tdesc = strings.ReplaceAll(desc, \"\\n\\n\", \"\")\n\t\tdesc = strings.TrimSpace(desc)\n\t\tshorthand[\"shorthandDesc\"] = desc\n\n\t\tmd := shorthand[\"shorthandContent\"].(string)\n\t\tshorthand[\"shorthandMd\"] = md\n\t\ttree := parse.Parse(\"\", []byte(md), luteEngine.ParseOptions)\n\t\tluteEngine.RenderOptions.ProtyleMarkNetImg = false\n\t\tcontent := luteEngine.ProtylePreview(tree, luteEngine.RenderOptions, luteEngine.ParseOptions)\n\t\tshorthand[\"shorthandContent\"] = content\n\t}\n\treturn\n}\n\nvar (\n\terrInvalidUser       = errors.New(\"invalid user\")\n\terrRequestUserFailed = errors.New(\"request user failed\")\n)\n\nfunc getUser(token string) (*conf.User, error) {\n\tresult := map[string]any{}\n\trequest := httpclient.NewCloudRequest30s().SetRetryCount(0)\n\tresp, err := request.\n\t\tSetSuccessResult(&result).\n\t\tSetBody(map[string]string{\"token\": token}).\n\t\tPost(util.GetCloudServer() + \"/apis/siyuan/user\")\n\tif err != nil {\n\t\tlogging.LogErrorf(\"get community user failed: %s\", err)\n\t\treturn nil, errRequestUserFailed\n\t}\n\tif http.StatusOK != resp.StatusCode {\n\t\tlogging.LogErrorf(\"get community user failed: %d\", resp.StatusCode)\n\t\tif http.StatusUnauthorized == resp.StatusCode {\n\t\t\treturn nil, errInvalidUser","sourceCodeStart":681,"sourceCodeEnd":717,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/cloud_service.go#L681-L717","documentation":"errInvalidUser (\"invalid user\") is returned by getUser when the SiYuan cloud /apis/siyuan/user endpoint answers HTTP 401 Unauthorized for the supplied token — the token definitively does not identify a valid user. Callers detect it via model.IsInvalidUserRefresh(err), and resolveCloudUserRefresh treats it as authoritative: the local user is logged out and the invalidation is broadcast to the UI.","triggerScenarios":"RefreshUser/getUser called with an expired, revoked, or malformed UserToken; the /user API responding 401; tests (TestResolveCloudUserRefresh) verifying the invalid-user refresh path.","commonSituations":"Token expiry after long uptime; the same account logging in on another device and invalidating the session; server-side account suspension or deletion; a token restored from an old backup config.","solutions":["Log in again to obtain a fresh token (Settings - Account or the login API); the local session is cleared once this error surfaces.","Do not retry with the same token — 401 is conclusive and resolveCloudUserRefresh will force a logout.","Use model.IsInvalidUserRefresh(err) in custom integrations to distinguish auth failure from transient network errors (which yield errRequestUserFailed instead).","If the account should be valid, verify it still exists and is active on the SiYuan cloud service."],"exampleFix":"// before\nuser, err := model.RefreshUser() // treat all errors the same\n// after\nuser, err := model.RefreshUser()\nif model.IsInvalidUserRefresh(err) {\n    model.LogoutUser() // token invalid; require fresh login\n    return\n}\nif err != nil {\n    // transient failure: safe to retry later\n}","handlingStrategy":"try-catch","validationCode":"// verify refresh outcome before relying on the user\nuser, err := model.RefreshUser()\nif err != nil && model.IsInvalidUserRefresh(err) { /* force re-login */ }","typeGuard":"func isAuthFatal(err error) bool { return model.IsInvalidUserRefresh(err) }","tryCatchPattern":"if _, err := model.RefreshUser(); model.IsInvalidUserRefresh(err) {\n    model.LogoutUser()\n    // surface login UI; do NOT retry with old token\n}","preventionTips":["Always branch on IsInvalidUserRefresh vs other errors — only the former needs re-login","Listen for the \"setCloudUser\" broadcast with a userName to notify users which account expired","Avoid reusing tokens restored from backups","Keep accounts active on the SiYuan cloud service"],"tags":["cloud","authentication","token-expired","siyuan"],"backgroundTag":"jwt-token-expired","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}