gotify/server · error
database error: %v
Error message
database error: %v
What it means
handleElevationCallback (api/oidc.go:260) returns HTTP 500 'database error: %v' when a.DB.GetClientByID(elevate.ClientID) returns a hard error while resolving the client referenced by the pending elevation session. Unlike the 404 case, this means the lookup itself failed (connection, query, or driver error), not that the client is missing.
Source
Thrown at api/oidc.go:260
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
}
if client == nil || client.UserID != user.ID {
http.Error(w, "client not found", http.StatusNotFound)
return
}
elevatedUntil := time.Now().Add(time.Duration(elevate.DurationSeconds) * time.Second)
if err := a.DB.UpdateClientElevatedUntil(client.ID, &elevatedUntil); err != nil {
http.Error(w, fmt.Sprintf("failed to elevate session: %v", err), http.StatusInternalServerError)
return
}
// The UI rechecks the authentication when the tab is closed.
w.WriteHeader(http.StatusOK)
w.Header().Add("content-type", "text/html")
io.WriteString(w, `<!DOCTYPE html>
<html lang="en">
<head>View on GitHub (pinned to 14bfc25627)
Solutions
- Read the wrapped driver error and check database connectivity/health from the gotify host
- Retry the elevation flow after the database recovers (a fresh state is required)
- Check for schema mismatches and run pending migrations
- Increase connection-pool/timeout settings if the error is a timeout under load
- Inspect DB server logs for the corresponding error at the same timestamp
Defensive patterns
Strategy: retry
Validate before calling
// Before driving users through the elevation flow, confirm the DB answers
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
// defer or skip the elevation flow until connectivity is restored
return
} Try / catch
c, err := db.GetClientByID(id)
if err != nil {
if isTransient(err) { // net.Error, driver.ErrBadConn, context deadline
return retryWithBackoff(err)
}
return fmt.Errorf("get client by id: %w", err)
} Prevention
- Monitor DB connectivity and set sane connect/read timeouts
- Pin schema versions with migrations so queries never hit missing columns
- Use a connection pool with health checks (ConnMaxLifetime, ping on acquire)
- Alert on client-lookup failures at the DB layer
- Prefer retrying transient network errors before surfacing 500s to users
When it happens
Trigger: The OIDC elevation flow (ElevateHandler -> provider -> CallbackHandler -> handleElevationCallback) reaches GetClientByID and the DB layer errors: connection refused/dropped, timeout, SQL syntax or schema error, or driver-level failure.
Common situations: Database restarted or unreachable mid-session; connection pool exhausted under load; schema drift after an upgrade; transient network partition between gotify and a remote Postgres.
Related errors
- failed to elevate session: %v
- failed to bind user to OIDC identity: %w
- failed to create user: %w
- failed to create client: %v
- issuer claim was empty
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/6fc89af32e1c3bfb.
Report an issue: GitHub.