ory/hydra · error

failed to set token lifespans due to failed client type asse

Error message

failed to set token lifespans due to failed client type assertion

What it means

MemoryStore.SetTokenLifespans only supports clients stored as *fosite.DefaultClientWithCustomTokenLifespans. If a client with the given ID exists but is a different concrete type in the store's map, it returns an RFC6749 error about the failed type assertion instead of applying the lifespans.

Source

Thrown at fosite/storage/memory.go:263

	defer s.clientsMutex.RUnlock()

	cl, ok := s.Clients[id]
	if !ok {
		return nil, fosite.ErrNotFound
	}
	return cl, nil
}

func (s *MemoryStore) SetTokenLifespans(clientID string, lifespans *fosite.ClientLifespanConfig) error {
	s.clientsMutex.RLock()
	defer s.clientsMutex.RUnlock()

	if client, ok := s.Clients[clientID]; ok {
		if clc, ok := client.(*fosite.DefaultClientWithCustomTokenLifespans); ok {
			clc.SetTokenLifespans(lifespans)
			return nil
		}
		return fosite.ErrorToRFC6749Error(errors.New("failed to set token lifespans due to failed client type assertion"))
	}
	return fosite.ErrNotFound
}

func (s *MemoryStore) ClientAssertionJWTValid(_ context.Context, jti string) error {
	s.blacklistedJTIsMutex.RLock()
	defer s.blacklistedJTIsMutex.RUnlock()

	if exp, exists := s.BlacklistedJTIs[jti]; exists && exp.After(time.Now()) {
		return fosite.ErrJTIKnown
	}

	return nil
}

func (s *MemoryStore) SetClientAssertionJWT(_ context.Context, jti string, exp time.Time) error {
	s.blacklistedJTIsMutex.Lock()
	defer s.blacklistedJTIsMutex.Unlock()

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Store clients as *fosite.DefaultClientWithCustomTokenLifespans (which embeds TokenLifespans) when seeding the MemoryStore
  2. Replace the existing client entry with the correct type before calling SetTokenLifespans
  3. If the client type cannot change, skip SetTokenLifespans and configure lifespans on the client at registration time

Example fix

// before
store.Clients[clientID] = &fosite.DefaultClient{ID: clientID}
store.SetTokenLifespans(ctx, clientID, lifespans)
// after
store.Clients[clientID] = &fosite.DefaultClientWithCustomTokenLifespans{
    DefaultClient: &fosite.DefaultClient{ID: clientID},
}
store.SetTokenLifespans(ctx, clientID, lifespans)
Defensive patterns

Strategy: type-guard

Type guard

func canSetLifespans(client fosite.Client) bool {
    _, ok := client.(*fosite.DefaultClientWithCustomTokenLifespans)
    return ok
}

Try / catch

if err := store.SetTokenLifespans(ctx, clientID, lifespans); err != nil {
    var rfcErr *fosite.RFC6749Error
    if errors.As(err, &rfcErr) {
        // re-register the client with the correct type, then retry
    }
}

Prevention

When it happens

Trigger: Calling SetTokenLifespans(ctx, clientID, lifespans) on a MemoryStore where s.Clients[clientID] was registered as a *fosite.DefaultClient (or any type other than *fosite.DefaultClientWithCustomTokenLifespans).

Common situations: Tests or in-memory setups seeding clients with the plain DefaultClient type but later trying to set custom token lifespans; migration from an older client type that lacks the TokenLifespans support embedded struct.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/076cb934a186042c. Report an issue: GitHub.