gotify/server · error
err.Error()
Error message
err.Error()
What it means
The OIDC CallbackHandler resolves the authenticated user from ID token claims and userinfo. On failure it writes the resolver's error message and its HTTP status directly to the response, so the client sees the raw resolveUser error text.
Source
Thrown at api/oidc.go:228
// - name: state
// in: query
// description: the state parameter for CSRF protection
// required: true
// type: string
// responses:
// 200:
// description: ok
// 307:
// description: Redirect to UI
// default:
// description: Error
// schema:
// $ref: "#/definitions/Error"
func (a *OIDCAPI) CallbackHandler() gin.HandlerFunc {
callback := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens[*oidc.IDTokenClaims], state string, provider rp.RelyingParty, info *oidc.UserInfo) {
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
}View on GitHub (pinned to 14bfc25627)
Solutions
- Read the response body's error text and status to identify which resolution step failed
- Configure the OIDC provider to include the required claims (e.g. email, preferred_username) in the ID token
- Check server logs for the underlying error from resolveUser
- Verify the user database is reachable and not read-only
Defensive patterns
Strategy: try-catch
Try / catch
resp, err := http.Get(callbackURL)
if resp.StatusCode >= 400 {
body, _ := io.ReadAll(resp.Body)
msg := string(body)
switch {
case strings.Contains(msg, "claim"):
log.Printf("OIDC provider claim config issue: %s", msg)
case strings.Contains(msg, "not found"):
log.Printf("user provisioning failed: %s", msg)
default:
log.Printf("callback error (%d): %s", resp.StatusCode, msg)
}
} Prevention
- Configure the OIDC provider to release all required claims
- Test the full login flow with the real provider in staging
- Log resolveUser failures server-side with context for debugging
- Map provider errors to user-friendly messages client-side
When it happens
Trigger: resolveUser returns an error during the OIDC callback — e.g. required claims (username/email) missing from the token, or user provisioning/matching against the database failing.
Common situations: OIDC provider not configured to release the claims Gotify requires, email not verified, or database issues while creating/matching the user at first login.
Related errors
- token exchange failed: %w
- issuer url %q is not a valid url: %w
- issuer url %q may not contain a fragment
- unknown or expired state
- issuer claim was empty
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/20ed67c613b1203d.
Report an issue: GitHub.