{"record":{"id":"cb39b4a327947d23","repo":"siyuan-note/siyuan","slug":"requestresult-msg","errorCode":null,"errorMessage":"requestResult.Msg","messagePattern":"requestResult\\.Msg","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/cloud_service.go","lineNumber":74,"sourceCode":"\t\t\"role\":    \"user\",\n\t\t\"content\": msg,\n\t})\n\tpayload[\"messages\"] = messages\n\n\trequestResult := gulu.Ret.NewResult()\n\trequest := httpclient.NewCloudRequest30s()\n\t_, err = request.\n\t\tSetSuccessResult(requestResult).\n\t\tSetCookies(&http.Cookie{Name: \"symphony\", Value: Conf.GetUser().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 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)\n\tret = message[\"content\"].(string)\n\n\tif nil != choice[\"finish_reason\"] {\n\t\tfinishReason := choice[\"finish_reason\"].(string)\n\t\tif \"length\" == finishReason {\n\t\t\tstop = false","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/cloud_service.go#L56-L92","documentation":"In CloudChatGPT, when the cloud server responds with a non-zero requestResult.Code, the server's requestResult.Msg string is wrapped in errors.New and returned with stop=true. This is a pass-through of a business-logic error from the cloud AI endpoint (e.g. quota exhausted, model unavailable, content policy).","triggerScenarios":"The POST to /apis/siyuan/ai/chatGPT succeeds at the HTTP layer (no transport error, not a 401) but the JSON result envelope carries Code != 0. The Msg field holds the human-readable reason from the server.","commonSituations":"AI subscription quota used up; the user's plan does not include AI access; the cloud rejected the prompt on content policy; transient server-side AI provider outage surfaced as a non-zero code.","solutions":["Display requestResult.Msg to the user as it carries the authoritative reason.","If the message indicates quota/plan limits, guide the user to upgrade or wait for quota reset.","Retry on transient server errors, but not on quota/policy codes.","Confirm the user is signed in and has an active subscription before retrying."],"exampleFix":"// before\nret, stop, err := CloudChatGPT(msg, ctx)\nif err != nil { log.Println(err) }\n\n// after\nret, stop, err := CloudChatGPT(msg, ctx)\nif err != nil {\n    if errors.Is(err, model.ErrFailedToConnectCloudServer) {\n        // network issue\n    } else {\n        showUser(err.Error()) // server-provided Msg\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check subscription before calling the AI endpoint\nif Conf.GetUser() == nil || !Conf.GetUser().IsAIEnabled() { return errors.New(\"AI not available for this account\") }","typeGuard":"func isServerBusinessError(err error) bool {\n    return err != nil && !errors.Is(err, model.ErrFailedToConnectCloudServer) && !isAuthError(err)\n}","tryCatchPattern":"_, _, err := model.CloudChatGPT(msg, ctx)\nif err != nil {\n    if errors.Is(err, model.ErrFailedToConnectCloudServer) { handleNetwork() }\n    else if isAuthError(err) { routeToLogin() }\n    else { showUser(err.Error()) /* server Msg, do not retry quota/policy errors */ }\n}","preventionTips":["Verify the user has an active AI-capable subscription before offering the feature.","Do not retry on quota/content-policy errors; only on transient ones.","Display the server-provided Msg verbatim to the user."],"tags":["cloud","ai","chatgpt","cloud-service","api-error"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}