gotify/server · critical
failed to bind user to OIDC identity: %w
Error message
failed to bind user to OIDC identity: %w
What it means
linkExistingUser wraps a failure from DB.UpdateUser while persisting the newly bound OIDCID (and possibly the Admin flag) as 'failed to bind user to OIDC identity: %w' with HTTP 500. Authentication and lookup succeeded, but the binding write failed so the link is not established.
Source
Thrown at api/oidc.go:498
}
return a.registerUser(username, oidcID, hasAdminGroup)
}
func (a *OIDCAPI) linkExistingUser(user *model.User, oidcID string, hasAdminGroup bool) (*model.User, int, error) {
if !a.LinkByUsername {
log.Warn().Str("oidc_id", oidcID).Str("username", user.Name).Msgf("OIDC login rejected: a local user with the username already exists and %s is disabled", config.EnvOIDCLinkByUsername)
return nil, http.StatusForbidden, fmt.Errorf("a local user with the username %s already exists and linking by username is disabled", user.Name)
}
if user.OIDCID != nil {
log.Warn().Str("oidc_id", oidcID).Str("bound_oidc_id", *user.OIDCID).Str("username", user.Name).Msg("OIDC login rejected: the username is already bound to a different OIDC identity")
return nil, http.StatusForbidden, fmt.Errorf("the user %s is already bound to a different OIDC identity", user.Name)
}
user.OIDCID = &oidcID
if len(a.GroupsAdmin) > 0 {
user.Admin = hasAdminGroup
}
if err := a.DB.UpdateUser(user); err != nil {
return nil, http.StatusInternalServerError, fmt.Errorf("failed to bind user to OIDC identity: %w", err)
}
log.Warn().Str("oidc_id", oidcID).Str("username", user.Name).Bool("admin", user.Admin).Msg("OIDC link by username")
return user, 0, nil
}
func (a *OIDCAPI) registerUser(username, oidcID string, hasAdminGroup bool) (*model.User, int, error) {
if !a.AutoRegister {
return nil, http.StatusForbidden, errors.New("user does not exist and auto-registration is disabled")
}
user := &model.User{
Name: username,
Pass: nil,
OIDCID: &oidcID,
}
if len(a.GroupsAdmin) > 0 {
user.Admin = hasAdminGroup
}View on GitHub (pinned to 14bfc25627)
Solutions
- Read the wrapped driver error in logs and fix the underlying storage issue
- Verify the users table schema supports the oidc_id column (run migrations)
- Retry the login; the next attempt will re-run the link
- Avoid concurrent first logins for the same account during migration
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure schema supports oidc_id before enabling OIDC
var count int
_ = db.QueryRow("SELECT COUNT(*) FROM information_schema.columns WHERE table_name='users' AND column_name='oidc_id'").Scan(&count)
if count == 0 { return errors.New("run migrations: users.oidc_id missing") } Try / catch
user, status, err := resolveUser(...)
if err != nil && strings.Contains(err.Error(), "failed to bind user to OIDC identity") {
log.Error().Err(err).Msg("OIDC bind failed; check DB")
http.Error(w, "temporary server error", http.StatusInternalServerError)
return
} Prevention
- Run migrations on every deploy
- Avoid concurrent first logins during migrations
- Add uniqueness/index constraints matching UpdateUser expectations
- Alert on UpdateUser failures
When it happens
Trigger: user.OIDCID = &oidcID and optional Admin update are set, then a.DB.UpdateUser(user) returns an error during a link-by-username login.
Common situations: DB connectivity loss; optimistic-lock/concurrent-update conflicts when the same user logs in from two sessions; NOT NULL/length constraints on oidc_id column; schema not migrated for the OIDCID column.
Related errors
- failed to create user: %w
- failed to create client: %v
- database error: %v
- failed to elevate session: %v
- issuer claim was empty
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/1179b87f97da249d.
Report an issue: GitHub.