{"record":{"id":"01602e7793cfb13e","repo":"mattermost-community/focalboard","slug":"unable-to-update-password","errorCode":null,"errorMessage":"unable to update password","messagePattern":"unable to update password","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/app/auth.go","lineNumber":227,"sourceCode":"\t\tvar err error\n\t\tuser, err = a.store.GetUserByID(userID)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"invalid username or password\")\n\t\t}\n\t}\n\n\tif user == nil {\n\t\treturn errors.New(\"invalid username or password\")\n\t}\n\n\tif !auth.ComparePassword(user.Password, oldPassword) {\n\t\ta.logger.Debug(\"Invalid password for user\", mlog.String(\"userID\", user.ID))\n\t\treturn errors.New(\"invalid username or password\")\n\t}\n\n\terr := a.store.UpdateUserPasswordByID(userID, auth.HashPassword(newPassword))\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"unable to update password\")\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":209,"sourceCodeEnd":232,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/app/auth.go#L209-L232","documentation":"This error is wrapped around the store's UpdateUserPasswordByID failure inside ChangePassword. It means the user was authenticated (userID resolved and old password matched) but persisting the new hashed password to storage failed. The original store error is preserved as the cause via errors.Wrap.","triggerScenarios":"Calling ChangePassword with valid credentials when a.store.UpdateUserPasswordByID returns an error: database unreachable, users table missing or schema mismatch, write rejected (read-only credentials, disk full), or the user row was deleted concurrently between the lookup and the update.","commonSituations":"Database outage or connection pool exhaustion during a password change; migration drift so the password column differs from the model; concurrent user deletion racing the update; SQLite file lock contention in single-user deployments.","solutions":["Log the error with %+v to reveal the wrapped store error and address the underlying database problem","Verify database connectivity and that the storage backend is writable","Retry the change once the database is healthy; confirm the user row still exists","Check schema migrations are up to date for the users table"],"exampleFix":"// before: swallowing detail\nif err := app.ChangePassword(userID, old, new); err != nil {\n    http.Error(w, \"something went wrong\", 500)\n}\n\n// after: surface the cause chain for diagnosis\nif err := app.ChangePassword(userID, old, new); err != nil {\n    log.Printf(\"password update failed: %+v\", err)\n    http.Error(w, \"could not update password, check database health\", 500)\n}","handlingStrategy":"retry","validationCode":"// Go: confirm DB writability before the password change\nif err := db.Ping(); err != nil {\n    return errors.Wrap(err, \"database unreachable\")\n}\nif _, err := store.GetUserByID(userID); err != nil {\n    return errors.Wrap(err, \"user must exist before password update\")\n}","typeGuard":null,"tryCatchPattern":"err := app.ChangePassword(userID, oldPassword, newPassword)\nfor attempt := 0; err != nil && attempt < 2; attempt++ {\n    time.Sleep(time.Duration(1<<attempt) * 100 * time.Millisecond)\n    err = app.ChangePassword(userID, oldPassword, newPassword)\n}\nif err != nil {\n    log.Printf(\"password update failed after retries: %+v\", err)\n}","preventionTips":["Monitor database connectivity and disk space; alert on write failures","Keep schema migrations current so the users table matches the model","Use bounded retries with backoff for transient store errors","Verify the user was not deleted concurrently before/while updating"],"tags":["go","auth","password-change","database"],"backgroundTag":"database-write-failed","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}