ory/hydra · error
server_error
server_error
Error message
{"error":"server_error","error_description":"%s"} What it means
In fosite's WriteAuthorizeError, when the error is not meant to redirect back to the client (e.g. invalid client or no redirect URI registered), fosite writes the error as a JSON body. If json.Marshal(rfcerr) then fails, and SendDebugMessagesToClients is enabled, it emits {"error":"server_error","error_description":"<marshal error>"} with status 500 — the same last-resort path as access_error.go, in the authorize endpoint.
Source
Thrown at fosite/authorize_error.go:30
func (f *Fosite) WriteAuthorizeError(ctx context.Context, rw http.ResponseWriter, ar AuthorizeRequester, err error) {
rw.Header().Set("Cache-Control", "no-store")
rw.Header().Set("Pragma", "no-cache")
if f.ResponseModeHandler(ctx).ResponseModes().Has(ar.GetResponseMode()) {
f.ResponseModeHandler(ctx).WriteAuthorizeError(ctx, rw, ar, err)
return
}
rfcerr := ErrorToRFC6749Error(err).WithLegacyFormat(f.Config.GetUseLegacyErrorFormat(ctx)).WithExposeDebug(f.Config.GetSendDebugMessagesToClients(ctx)).WithLocalizer(f.Config.GetMessageCatalog(ctx), getLangFromRequester(ar))
if !ar.IsRedirectURIValid() {
rw.Header().Set("Content-Type", "application/json;charset=UTF-8")
js, err := json.Marshal(rfcerr)
if err != nil {
if f.Config.GetSendDebugMessagesToClients(ctx) {
errorMessage := EscapeJSONString(err.Error())
http.Error(rw, fmt.Sprintf(`{"error":"server_error","error_description":"%s"}`, errorMessage), http.StatusInternalServerError)
} else {
http.Error(rw, `{"error":"server_error"}`, http.StatusInternalServerError)
}
return
}
rw.WriteHeader(rfcerr.CodeField)
_, _ = rw.Write(js)
return
}
redirectURI := ar.GetRedirectURI()
// The endpoint URI MUST NOT include a fragment component.
redirectURI.Fragment = ""
errors := rfcerr.ToValues()
errors.Set("state", ar.GetState())View on GitHub (pinned to 4174065ffb)
Solutions
- Fix the root cause of the authorize error first (valid client_id and redirect_uri registration) so the redirect branch is used instead of JSON rendering.
- Audit custom authorize handlers and storage errors for non-serializable values attached to fosite errors.
- Disable SendDebugMessagesToClients in production so marshal failures return the generic {"error":"server_error"} body.
- Add a regression test marshaling your custom error type through WriteAuthorizeError.
Example fix
// before
return errors.Wrapf(err, "db fail: %v", conn) // conn may be unserializable when fosite re-wraps
// after
return fosite.ErrServerError.WithHint("storage unavailable")
// and register redirect URIs so errors redirect instead of JSON-rendering:
// client.RedirectURIs = []string{"https://app.example.com/callback"} Defensive patterns
Strategy: try-catch
Validate before calling
// Verify client registration prevents the JSON branch (always provide a valid redirect):
if len(client.GetRedirectURIs()) == 0 {
return errors.New("client has no registered redirect URIs — authorize errors will JSON-render")
} Type guard
func authorizeErrorRedirectable(err *fosite.RFC6749Error) bool {
return err.ReasonCode != fosite.ErrInvalidRequestURI.ReasonCode && len(err.Hint) > 0
} Try / catch
// Ensure errors redirect where possible; wrap WriteAuthorizeError to log first:
func writeAuthorizeError(ctx context.Context, f *fosite.Fosite, rw http.ResponseWriter, ar fosite.AccessRequester, err error) {
log.Printf("authorize error: %v", err)
f.WriteAuthorizeError(ctx, rw, ar, err)
} Prevention
- Register valid redirect_uri values for all clients so errors use the redirect branch
- Only attach string-safe hints/descriptions to fosite errors
- Disable SendDebugMessagesToClients in production
- Test your custom authorize handlers end-to-end with invalid clients to exercise the JSON branch
When it happens
Trigger: WriteAuthorizeError takes the JSON branch (no valid redirect possible) and json.Marshal(rfcerr) fails at fosite/authorize_error.go:30 — custom error/args values attached by an authorize handler containing channels, funcs, or cyclic references; also triggered when the client's redirect URI is invalid so fosite must render JSON instead of redirecting.
Common situations: Authorization requests with unregistered client_id or disallowed redirect_uri (forces the JSON branch) combined with custom handlers that stash unserializable data on the error; debug mode enabled; custom storage returning errors wrapped with unserializable context.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- failed to set token lifespans due to failed client type asse
- a secret for signing HMAC-SHA512/256 is expected to be defin
- Session must be of type JWTSessionContainer but got type: %T
- GetTokenClaims() must not be nil
- secret for signing HMAC-SHA512/256 is expected to be 32 byte
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/9db8c4051546f2b2.
Report an issue: GitHub.