From 94e1504e2be008bc6058b987c632eacf67b094ce Mon Sep 17 00:00:00 2001 From: Evan Baker Date: Mon, 25 May 2026 10:02:21 -0500 Subject: [PATCH] fix(user): stop double-encoding FrontendSettings on UpdateUser UpdateUser was manually json.Marshal'ing user.FrontendSettings and re-assigning the []byte back to the interface{} field before passing the user to xorm. The column is declared: FrontendSettings interface{} `xorm:"json null" json:"-"` xorm's `json` modifier already marshals the field on write. Pre-marshalling to []byte and stuffing it back into the interface causes xorm to JSON-encode a []byte (which serializes as a base64 string). The DB ends up storing `"bnVsbA=="` (base64 of "null") for users whose FrontendSettings is nil, or a double-encoded blob for users with real settings. On read, xorm unmarshals that string back into the interface as a Go `string`, and the API response then contains: "frontend_settings": "bnVsbA==" instead of a JSON object or null. The Flutter mobile client (go-vikunja/app) typed-casts `frontend_settings` to `Map?` and crashes with: type 'String' is not a subtype of type 'Map?' which the app surfaces as "could not connect to this server". The web client tolerates it silently (JS spread over a string). Trigger path: every OIDC login of an existing user calls UpdateUser (pkg/modules/auth/openid/openid.go), so the row is corrupted on every re-login. See go-vikunja/app#265. Fix: let xorm handle the JSON marshalling as the struct tag advertises. Drop the now-unused encoding/json import. --- pkg/user/user.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/user/user.go b/pkg/user/user.go index 09fef2565..ec165f746 100644 --- a/pkg/user/user.go +++ b/pkg/user/user.go @@ -18,7 +18,6 @@ package user import ( "context" - "encoding/json" "errors" "fmt" "net/mail" @@ -633,12 +632,6 @@ func UpdateUser(s *xorm.Session, user *User, forceOverride bool) (updatedUser *U return nil, &ErrInvalidTimezone{Name: user.Timezone, LoadError: err} } - frontendSettingsJSON, err := json.Marshal(user.FrontendSettings) - if err != nil { - return nil, err - } - user.FrontendSettings = frontendSettingsJSON - // Update it _, err = s. ID(user.ID).