siyuan-note/siyuan · error

invalid user

Error message

invalid user

What it means

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.

Source

Thrown at kernel/model/cloud_service.go:699

		desc = audioRegexp.ReplaceAllString(desc, " 语音 ")
		desc = videoRegexp.ReplaceAllString(desc, " 视频 ")
		desc = fileRegexp.ReplaceAllString(desc, " 文件 ")
		desc = strings.ReplaceAll(desc, "\n\n", "")
		desc = strings.TrimSpace(desc)
		shorthand["shorthandDesc"] = desc

		md := shorthand["shorthandContent"].(string)
		shorthand["shorthandMd"] = md
		tree := parse.Parse("", []byte(md), luteEngine.ParseOptions)
		luteEngine.RenderOptions.ProtyleMarkNetImg = false
		content := luteEngine.ProtylePreview(tree, luteEngine.RenderOptions, luteEngine.ParseOptions)
		shorthand["shorthandContent"] = content
	}
	return
}

var (
	errInvalidUser       = errors.New("invalid user")
	errRequestUserFailed = errors.New("request user failed")
)

func getUser(token string) (*conf.User, error) {
	result := map[string]any{}
	request := httpclient.NewCloudRequest30s().SetRetryCount(0)
	resp, err := request.
		SetSuccessResult(&result).
		SetBody(map[string]string{"token": token}).
		Post(util.GetCloudServer() + "/apis/siyuan/user")
	if err != nil {
		logging.LogErrorf("get community user failed: %s", err)
		return nil, errRequestUserFailed
	}
	if http.StatusOK != resp.StatusCode {
		logging.LogErrorf("get community user failed: %d", resp.StatusCode)
		if http.StatusUnauthorized == resp.StatusCode {
			return nil, errInvalidUser

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Log in again to obtain a fresh token (Settings - Account or the login API); the local session is cleared once this error surfaces.
  2. Do not retry with the same token — 401 is conclusive and resolveCloudUserRefresh will force a logout.
  3. Use model.IsInvalidUserRefresh(err) in custom integrations to distinguish auth failure from transient network errors (which yield errRequestUserFailed instead).
  4. If the account should be valid, verify it still exists and is active on the SiYuan cloud service.

Example fix

// before
user, err := model.RefreshUser() // treat all errors the same
// after
user, err := model.RefreshUser()
if model.IsInvalidUserRefresh(err) {
    model.LogoutUser() // token invalid; require fresh login
    return
}
if err != nil {
    // transient failure: safe to retry later
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify refresh outcome before relying on the user
user, err := model.RefreshUser()
if err != nil && model.IsInvalidUserRefresh(err) { /* force re-login */ }

Type guard

func isAuthFatal(err error) bool { return model.IsInvalidUserRefresh(err) }

Try / catch

if _, err := model.RefreshUser(); model.IsInvalidUserRefresh(err) {
    model.LogoutUser()
    // surface login UI; do NOT retry with old token
}

Prevention

When it happens

Trigger: RefreshUser/getUser called with an expired, revoked, or malformed UserToken; the /user API responding 401; tests (TestResolveCloudUserRefresh) verifying the invalid-user refresh path.

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2389c85385f40bff. Report an issue: GitHub.