{"record":{"id":"e90010657eb56d7b","repo":"siyuan-note/siyuan","slug":"conf-language-31-localized-not-logged-in-login-expired","errorCode":null,"errorMessage":"Conf.Language(31) (localized: not logged in / login expired)","messagePattern":"Conf\\.Language\\(31\\) \\(localized: not logged in / login expired\\)","errorType":"exception","errorClass":null,"httpStatus":401,"severity":"error","filePath":"kernel/model/cloud_service.go","lineNumber":77,"sourceCode":"\t\t\"content\": msg,\n\t})\n\tpayload[\"messages\"] = messages\n\n\trequestResult := gulu.Ret.NewResult()\n\trequest := httpclient.NewCloudRequest30s()\n\tresp, err := request.\n\t\tSetSuccessResult(requestResult).\n\t\tSetCookies(&http.Cookie{Name: \"symphony\", Value: user.UserToken}).\n\t\tSetBody(payload).\n\t\tPost(util.GetCloudServer() + \"/apis/siyuan/ai/chatGPT\")\n\tif err != nil {\n\t\tlogging.LogErrorf(\"chat gpt failed: %s\", err)\n\t\terr = ErrFailedToConnectCloudServer\n\t\treturn\n\t}\n\tif http.StatusUnauthorized == resp.StatusCode {\n\t\tinvalidUser()\n\t\treturn \"\", true, errors.New(Conf.Language(31))\n\t}\n\tif http.StatusOK != resp.StatusCode {\n\t\treturn \"\", true, ErrFailedToConnectCloudServer\n\t}\n\tif 0 != requestResult.Code {\n\t\terr = errors.New(requestResult.Msg)\n\t\tstop = true\n\t\treturn\n\t}\n\n\tdata := requestResult.Data.(map[string]any)\n\tchoices := data[\"choices\"].([]any)\n\tif 1 > len(choices) {\n\t\tstop = true\n\t\treturn\n\t}\n\tchoice := choices[0].(map[string]any)\n\tmessage := choice[\"message\"].(map[string]any)","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/cloud_service.go#L59-L95","documentation":"CloudChatGPT (kernel/model/cloud_service.go:77) returns errors.New(Conf.Language(31)) — the localized 'not logged in / login expired' message — when the cloud AI endpoint responds HTTP 401. It also calls invalidUser(), which clears the cached account, so the next cloud call will see no user. This is an auth-state error, not a network error.","triggerScenarios":"Invoking AI chat while the cloud session token is expired or revoked (HTTP 401 from the ChatGPT proxy endpoint); token invalidated by logging in elsewhere or cloud-side session expiry.","commonSituations":"Long-lived desktop session whose token aged out; using AI features after the subscription/account became invalid; multiple devices causing token rotation.","solutions":["Log in again (Settings - Account) to refresh the cloud token, then retry the AI chat","After catching this error, note that invalidUser() already cleared the cached user; re-fetch the account instead of retrying with the old token","Check subscription status if the account is valid but the plan no longer covers AI features","In code, detect the localized message or better check user == nil before calling CloudChatGPT and prompt login first"],"exampleFix":"// before\nreply, stop, err := model.CloudChatGPT(msg, ctx)\n\n// after\nif model.Conf.GetUser() == nil {\n    ui.promptLogin() // localized Conf.Language(31) equivalent\n    return\n}\nreply, stop, err := model.CloudChatGPT(msg, ctx)\nif err != nil && model.Conf.GetUser() == nil { // invalidUser() fired -> 401 path\n    ui.promptLogin()\n}","handlingStrategy":"validation","validationCode":"if model.Conf.GetUser() == nil {\n    ui.promptLogin() // localized Conf.Language(31)\n    return\n}","typeGuard":"user := model.Conf.GetUser()\nif user == nil || user.UserToken == \"\" { promptLogin(); return }","tryCatchPattern":"if err != nil && model.Conf.GetUser() == nil { // 401 path cleared the user\n    promptLoginThen(func() { retryChat() })\n}","preventionTips":["Prompt for login before any cloud/AI feature when the cached user is nil","Remember invalidUser() clears the session on 401 — always re-authenticate, never retry with the old token","Refresh tokens proactively in long-lived desktop sessions"],"tags":["authentication","cloud","session-expired"],"backgroundTag":"authentication-required","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}