{"record":{"id":"7c8f83e4e3933734","repo":"ory/hydra","slug":"err-error-7c8f83","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"fosite/access_write.go","lineNumber":18,"sourceCode":"// Copyright © 2025 Ory Corp\n// SPDX-License-Identifier: Apache-2.0\n\npackage fosite\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc (f *Fosite) WriteAccessResponse(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) {\n\trw.Header().Set(\"Cache-Control\", \"no-store\")\n\trw.Header().Set(\"Pragma\", \"no-cache\")\n\n\tjs, err := json.Marshal(responder.ToMap())\n\tif err != nil {\n\t\thttp.Error(rw, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\trw.Header().Set(\"Content-Type\", \"application/json;charset=UTF-8\")\n\n\trw.WriteHeader(http.StatusOK)\n\t_, _ = rw.Write(js)\n}\n","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/fosite/access_write.go#L1-L27","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntype Session struct {\n\tCtx context.Context `json:\"ctx\"` // unserializable\n\tmu  sync.Mutex\n}\n// after\ntype Session struct {\n\tUserID string `json:\"sub\"`\n\tExpiry time.Time `json:\"exp\"`\n}","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(session.ToMap()); err != nil {\n\treturn fmt.Errorf(\"session not serializable: %w\", err)\n}","typeGuard":"func serializableSession(s fosite.Session) bool {\n\t_, err := json.Marshal(s)\n\treturn err == nil\n}","tryCatchPattern":"// Guard around WriteAccessResponse in your token handler:\nfunc safeWriteAccess(ctx context.Context, rw http.ResponseWriter, req fosite.AccessRequester, res fosite.AccessResponder) {\n\tdefer func() {\n\t\tif rec := recover(); rec != nil { log.Printf(\"access write panic: %v\", rec) }\n\t}()\n\tif js, err := json.Marshal(res.ToMap()); err != nil {\n\t\tlog.Printf(\"access response marshal failed: %v\", err)\n\t\tfosite.WriteRFC6749Error(rw, fosite.ErrServerError, true)\n\t\treturn\n\t}\n\tfosite.WriteAccessResponse(ctx, rw, req, res)\n}","preventionTips":["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"],"tags":["oauth2","fosite","json"],"backgroundTag":"json-marshal-failed","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}