ory/hydra · error
GetTokenClaims() must not be nil
Error message
GetTokenClaims() must not be nil
What it means
After a successful JWTSessionContainer assertion, generate() calls GetJWTClaims() and refuses to proceed if it returns nil. A JWT session without a claims object cannot produce a valid token payload, so fosite fails fast with this error.
Source
Thrown at fosite/handler/oauth2/strategy_jwt.go:92
case v.Has(jwt.ValidationErrorExpired):
return fosite.ErrTokenExpired
case v.Has(jwt.ValidationErrorAudience |
jwt.ValidationErrorIssuedAt |
jwt.ValidationErrorIssuer |
jwt.ValidationErrorNotValidYet |
jwt.ValidationErrorId |
jwt.ValidationErrorClaimsInvalid):
return fosite.ErrTokenClaim
default:
return fosite.ErrRequestUnauthorized
}
}
func (h *DefaultJWTStrategy) generate(ctx context.Context, tokenType fosite.TokenType, requester fosite.Requester) (string, string, error) {
if jwtSession, ok := requester.GetSession().(JWTSessionContainer); !ok {
return "", "", errors.Errorf("Session must be of type JWTSessionContainer but got type: %T", requester.GetSession())
} else if claims := jwtSession.GetJWTClaims(); claims == nil {
return "", "", errors.New("GetTokenClaims() must not be nil")
} else {
claims.
With(
jwtSession.GetExpiresAt(tokenType),
requester.GetGrantedScopes(),
requester.GetGrantedAudience(),
).
WithDefaults(
time.Now().UTC(),
h.Config.GetAccessTokenIssuer(ctx),
).
WithScopeField(
h.Config.GetJWTScopeField(ctx),
)
return h.Signer.Generate(ctx, claims.ToMapClaims(), jwtSession.GetJWTHeader())
}
}View on GitHub (pinned to 4174065ffb)
Solutions
- Initialize the claims object in your session constructor: sess.GetJWTClaims().With(...) or ensure GetJWTClaims() always returns a non-nil *jwt.JWTClaims
- Fix custom GetJWTClaims() to lazily create the claims struct if nil instead of returning nil
- Verify serialization/deserialization of sessions preserves the claims object
- Check that storage round-trips (cache, DB) don't strip claims from the session
Example fix
// before
func (s *MySession) GetJWTClaims() jwt.JWTClaimsContainer { return s.claims } // nil if unset
// after
func (s *MySession) GetJWTClaims() jwt.JWTClaimsContainer {
if s.claims == nil { s.claims = &jwt.JWTClaims{} }
return s.claims
} Defensive patterns
Strategy: type-guard
Validate before calling
if js, ok := req.GetSession().(JWTSessionContainer); ok && js.GetJWTClaims() == nil {
return errors.New("session has nil JWT claims; initialize claims before token generation")
} Type guard
func hasJWTClaims(s fosite.Session) bool {
js, ok := s.(JWTSessionContainer)
return ok && js.GetJWTClaims() != nil
} Try / catch
resp, err := oauth2Client.GetAccessToken(ctx, req)
if err != nil && strings.Contains(err.Error(), "GetTokenClaims() must not be nil") {
log.Fatalf("session misconfigured: claims were nil: %v", err)
} Prevention
- Initialize claims in your session constructor, never leave the claims field zero-valued
- Make GetJWTClaims() lazily allocate a non-nil claims object
- Include claims in session serialization (storage/cache round-trips)
- Add a unit test that generates a token from a freshly constructed session
When it happens
Trigger: Calling GenerateAccessToken with a session whose GetJWTClaims() returns nil — e.g. a JWTSessionContainer implementation that never initialized its claims field, or a session deserialized from storage with claims lost.
Common situations: Custom JWTSessionContainer implementations that lazily allocate claims but were constructed without them; copying session structs so the pointer to claims was nil; sessions restored from JSON where claims were omitted.
Related errors
- Session must be of type JWTSessionContainer but got type: %T
- failed to set token lifespans due to failed client type asse
- a secret for signing HMAC-SHA512/256 is expected to be defin
- header, body and signature must all be set
- Token is expired
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/8e3fd9f355b2dd75.
Report an issue: GitHub.