siyuan-note/siyuan · error

invalid cloud login message

Error message

invalid cloud login message

What it means

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.

Solutions

  1. Inspect the raw response body for the actual shape
  2. Retry the login to rule out a transient gateway error
  3. Verify client and cloud service protocol versions match
  4. If implementing a mock/server, always include a string msg field

Example fix

// before
{"code":0} // msg missing
// after
{"code":0,"msg":"","token":"..."}
Defensive patterns

Strategy: try-catch

Validate before calling

function hasMsgField(v: unknown): v is { code: number; msg: string } {
  return typeof v === 'object' && v !== null && typeof (v as any).msg === 'string' && (v as any).msg !== null;
}

Type guard

function isString(v: unknown): v is string { return typeof v === 'string'; }

Try / catch

try { const resp = await cloudLogin(user, pass); } catch (e) { if (String(e).includes('invalid cloud login message')) { log(e, lastRawBody); showCloudServiceError(); } }

Prevention

When it happens

Trigger: Unmarshalling a cloud login response JSON where 'msg' is absent, null, or a non-string value (number, object, array).

Common situations: Cloud backend omitting msg on success responses after a protocol update, or error responses from gateways that only include code without msg.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/a585c95aec138052. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/setting_cloud.go:46

		return nil, err
	}
	if fields["msg"], err = json.Marshal(d.Msg); err != nil {
		return nil, err
	}
	return json.Marshal(fields)
}

func (d *CloudLogin2faData) UnmarshalJSON(raw []byte) error {
	var fields map[string]json.RawMessage
	if err := json.Unmarshal(raw, &fields); err != nil {
		return err
	}
	code, msg := fields["code"], fields["msg"]
	if len(code) == 0 || bytes.Equal(code, []byte("null")) || json.Unmarshal(code, &d.Code) != nil {
		return errors.New("invalid cloud login code")
	}
	if len(msg) == 0 || bytes.Equal(msg, []byte("null")) || json.Unmarshal(msg, &d.Msg) != nil {
		return errors.New("invalid cloud login message")
	}
	if d.Code == 0 {
		var token string
		if json.Unmarshal(fields["token"], &token) != nil || token == "" {
			return errors.New("invalid cloud login token")
		}
	}
	d.Extra = make(map[string]JSONValue, len(fields)-2)
	for key, raw := range fields {
		if key == "code" || key == "msg" {
			continue
		}
		value, err := EncodedJSONValue(raw)
		if err != nil {
			return err
		}
		d.Extra[key] = value
	}

View on GitHub (pinned to 9f775e8a12)