gotify/server · error
failed to create client: %v
Error message
failed to create client: %v
What it means
After a successful OIDC callback, api/oidc.go:244 wraps any error from a.createClient(session.ClientName, user.ID) into an HTTP 500 'failed to create client: %v'. createClient persists a new client record (with token) for the authenticated user; failure means the client could not be stored even though OIDC authentication itself succeeded.
Source
Thrown at api/oidc.go:244
user, status, err := a.resolveUser(tokens.IDTokenClaims, info)
if err != nil {
http.Error(w, err.Error(), status)
return
}
session, ok := a.popPendingSession(state)
if !ok {
http.Error(w, "unknown or expired state", http.StatusBadRequest)
return
}
if session.Elevate != nil {
a.handleElevationCallback(w, session.Elevate, user)
return
}
client, err := a.createClient(session.ClientName, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to create client: %v", err), http.StatusInternalServerError)
return
}
auth.SetCookie(w, client.Token, auth.CookieMaxAge, a.SecureCookie)
// A reverse proxy may have already stripped a url prefix from the URL
// without us knowing, we have to make a relative redirect.
// We cannot use http.Redirect as this normalizes the Path with r.URL.
w.Header().Set("Location", "../../")
w.WriteHeader(http.StatusTemporaryRedirect)
}
return gin.WrapF(rp.CodeExchangeHandler(rp.UserinfoCallback(callback), a.Provider))
}
func (a *OIDCAPI) handleElevationCallback(w http.ResponseWriter, elevate *pendingElevation, user *model.User) {
client, err := a.DB.GetClientByID(elevate.ClientID)
if err != nil {
http.Error(w, fmt.Sprintf("database error: %v", err), http.StatusInternalServerError)
return
}View on GitHub (pinned to 14bfc25627)
Solutions
- Check the wrapped inner error in the response/log and verify database connectivity and health
- Confirm database migrations are up to date for the gotify version
- Retry the OIDC login once the database is healthy; the state was consumed, so start a new login
- If a duplicate-name constraint is the cause, retry with a different client name
- Inspect DB logs for lock/permission/disk errors during the insert
Defensive patterns
Strategy: retry
Validate before calling
// Before initiating the login that will create a client, verify the DB is reachable
if err := db.Ping(); err != nil {
return fmt.Errorf("database unavailable, fix before login: %w", err)
} Try / catch
client, err := createClient(name, userID)
if err != nil {
log.Printf("client creation failed: %v", err) // keep the wrapped cause
if errors.Is(err, sql.ErrNoRows) || isConstraintViolation(err) {
return retryWithNewName(name) // duplicate/conflict case
}
return retryWithBackoff(err) // transient DB error
} Prevention
- Monitor database health before/at login time
- Keep migrations applied when upgrading gotify
- Avoid retrying logins with an identical client name if name conflicts are possible
- Alert on insert failures in the clients table
- Ensure adequate disk space and connection-pool headroom
When it happens
Trigger: createClient fails while handling the provider callback: database unavailable or returning an error on insert, unique/name constraint violated by the requested client name, DB schema mismatch after an upgrade, or disk/storage errors during the insert.
Common situations: Postgres/SQLite down or connection pool exhausted during login; duplicate client name from retrying the login with the same name; migration not applied so the clients table lacks a column; database read-only or out of disk space.
Related errors
- failed to bind user to OIDC identity: %w
- failed to create user: %w
- 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/b0e5ed7fc673b0c9.
Report an issue: GitHub.