{"record":{"id":"a585c95aec138052","repo":"siyuan-note/siyuan","slug":"invalid-cloud-login-message","errorCode":null,"errorMessage":"invalid cloud login message","messagePattern":"invalid cloud login message","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/setting_cloud.go","lineNumber":46,"sourceCode":"\t\treturn nil, err\n\t}\n\tif fields[\"msg\"], err = json.Marshal(d.Msg); err != nil {\n\t\treturn nil, err\n\t}\n\treturn json.Marshal(fields)\n}\n\nfunc (d *CloudLogin2faData) UnmarshalJSON(raw []byte) error {\n\tvar fields map[string]json.RawMessage\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\tcode, msg := fields[\"code\"], fields[\"msg\"]\n\tif len(code) == 0 || bytes.Equal(code, []byte(\"null\")) || json.Unmarshal(code, &d.Code) != nil {\n\t\treturn errors.New(\"invalid cloud login code\")\n\t}\n\tif len(msg) == 0 || bytes.Equal(msg, []byte(\"null\")) || json.Unmarshal(msg, &d.Msg) != nil {\n\t\treturn errors.New(\"invalid cloud login message\")\n\t}\n\tif d.Code == 0 {\n\t\tvar token string\n\t\tif json.Unmarshal(fields[\"token\"], &token) != nil || token == \"\" {\n\t\t\treturn errors.New(\"invalid cloud login token\")\n\t\t}\n\t}\n\td.Extra = make(map[string]JSONValue, len(fields)-2)\n\tfor key, raw := range fields {\n\t\tif key == \"code\" || key == \"msg\" {\n\t\t\tcontinue\n\t\t}\n\t\tvalue, err := EncodedJSONValue(raw)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\td.Extra[key] = value\n\t}","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/setting_cloud.go#L28-L64","documentation":"Custom UnmarshalJSON error for CloudLogin2faData: the msg field of the cloud 2FA login response is absent, null, or not a string, so the response does not conform to the expected {code,msg} envelope and cannot be deserialized.","triggerScenarios":"Unmarshalling a cloud login response JSON where 'msg' is absent, null, or a non-string value (number, object, array).","commonSituations":"Cloud backend omitting msg on success responses after a protocol update, or error responses from gateways that only include code without msg.","solutions":["Inspect the raw response body for the actual shape","Retry the login to rule out a transient gateway error","Verify client and cloud service protocol versions match","If implementing a mock/server, always include a string msg field"],"exampleFix":"// before\n{\"code\":0} // msg missing\n// after\n{\"code\":0,\"msg\":\"\",\"token\":\"...\"}","handlingStrategy":"try-catch","validationCode":"function hasMsgField(v: unknown): v is { code: number; msg: string } {\n  return typeof v === 'object' && v !== null && typeof (v as any).msg === 'string' && (v as any).msg !== null;\n}","typeGuard":"function isString(v: unknown): v is string { return typeof v === 'string'; }","tryCatchPattern":"try { const resp = await cloudLogin(user, pass); } catch (e) { if (String(e).includes('invalid cloud login message')) { log(e, lastRawBody); showCloudServiceError(); } }","preventionTips":["Validate the full response schema, not just code","Treat missing msg as a service-side error and surface it to the user","Retry transient 5xx/HTML responses before parsing","Keep mock servers compliant with the real response shape"],"tags":["json","unmarshal","cloud","login"],"backgroundTag":"unexpected-response-shape","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"}