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

  1. Read the response body's error text and status to identify which resolution step failed
  2. Configure the OIDC provider to include the required claims (e.g. email, preferred_username) in the ID token
  3. Check server logs for the underlying error from resolveUser
  4. 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

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


AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05). Data as JSON: /api/errors/20ed67c613b1203d. Report an issue: GitHub.