ory/hydra · error
err.Error()
Error message
err.Error()
What it means
In fosite's WriteAccessResponse, if json.Marshal(responder.ToMap()) fails, the raw err.Error() text is written with status 500. ToMap flattens the access response (access_token, token_type, expires_in, scope, plus any session/extra fields); marshal failure means one of those values cannot be serialized — essentially always a custom session or extra-claims value containing unsupported types.
Source
Thrown at fosite/access_write.go:18
// Copyright © 2025 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package fosite
import (
"context"
"encoding/json"
"net/http"
)
func (f *Fosite) WriteAccessResponse(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) {
rw.Header().Set("Cache-Control", "no-store")
rw.Header().Set("Pragma", "no-cache")
js, err := json.Marshal(responder.ToMap())
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
rw.Header().Set("Content-Type", "application/json;charset=UTF-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(js)
}
View on GitHub (pinned to 4174065ffb)
Solutions
- Audit your custom Session/claims types: remove channels, funcs, mutexes, contexts, and cyclic references; expose only JSON-safe fields with proper tags.
- Implement/fix MarshalJSON on custom claim types so they serialize deterministically.
- Write a unit test marshaling your session type (like TestWriteAccessResponse) to catch this before production.
- Handle the 500 by returning a generic oauth server_error to clients instead of leaking err.Error() — wrap WriteAccessResponse in middleware.
Example fix
// before
type Session struct {
Ctx context.Context `json:"ctx"` // unserializable
mu sync.Mutex
}
// after
type Session struct {
UserID string `json:"sub"`
Expiry time.Time `json:"exp"`
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := json.Marshal(session.ToMap()); err != nil {
return fmt.Errorf("session not serializable: %w", err)
} Type guard
func serializableSession(s fosite.Session) bool {
_, err := json.Marshal(s)
return err == nil
} Try / catch
// Guard around WriteAccessResponse in your token handler:
func safeWriteAccess(ctx context.Context, rw http.ResponseWriter, req fosite.AccessRequester, res fosite.AccessResponder) {
defer func() {
if rec := recover(); rec != nil { log.Printf("access write panic: %v", rec) }
}()
if js, err := json.Marshal(res.ToMap()); err != nil {
log.Printf("access response marshal failed: %v", err)
fosite.WriteRFC6749Error(rw, fosite.ErrServerError, true)
return
}
fosite.WriteAccessResponse(ctx, rw, req, res)
} Prevention
- Keep custom Session structs free of context.Context, sync primitives, and closures
- Tag all custom claim fields with json tags and test marshaling them
- Run a test mirroring TestWriteAccessResponse against your session type
- Never leak internal request-scoped values into response extra fields
When it happens
Trigger: json.Marshal(responder.ToMap()) fails in fosite/access_write.go:18 — e.g. a custom AccessRequester/Session whose GetSession or extra map exposes channels, funcs, cyclic pointers, or a custom type with an erroring MarshalJSON. Reached from token endpoint handlers and exercised by TestWriteAccessResponse.
Common situations: Custom session structs storing context.Context, sync primitives (sync.Mutex), or time.Time alternatives with broken MarshalJSON; storing request-scoped closures in extra claims; injecting non-JSON types into IDToken claims that propagate into the access response map.
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
- server_error
- 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
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/7c8f83e4e3933734.
Report an issue: GitHub.