oauth2-proxy/oauth2-proxy · warning
session does not exist
Error message
session does not exist
What it means
SessionStore.Load reads session bytes from Redis by key. When the Redis GET returns redis.Nil (the key simply does not exist), the store translates it into the sentinel error "session does not exist". It exists to distinguish a normal cache miss from a real Redis failure.
Source
Thrown at pkg/sessions/redis/redis_store.go:53
return persistence.NewManager(rs, cookieOpts), nil
}
// Save takes a sessions.SessionState and stores the information from it
// to redis, and adds a new persistence cookie on the HTTP response writer
func (store *SessionStore) Save(ctx context.Context, key string, value []byte, exp time.Duration) error {
err := store.Client.Set(ctx, key, value, exp)
if err != nil {
return fmt.Errorf("error saving redis session: %v", err)
}
return nil
}
// Load reads sessions.SessionState information from a persistence
// cookie within the HTTP request object
func (store *SessionStore) Load(ctx context.Context, key string) ([]byte, error) {
value, err := store.Client.Get(ctx, key)
if err == redis.Nil {
return nil, fmt.Errorf("session does not exist")
} else if err != nil {
return nil, fmt.Errorf("error loading redis session: %v", err)
}
return value, nil
}
// Clear clears any saved session information for a given persistence cookie
// from redis, and then clears the session
func (store *SessionStore) Clear(ctx context.Context, key string) error {
err := store.Client.Del(ctx, key)
if err != nil {
return fmt.Errorf("error clearing the session from redis: %v", err)
}
return nil
}
// Lock creates a lock object for sessions.SessionStateView on GitHub (pinned to 33c2eb92de)
Solutions
- Treat this as an expected cache miss: re-authenticate the user and Save a fresh session instead of surfacing the error
- Check Redis TTL config and session cookie lifetime so they align (cookie outliving the Redis entry causes this)
- Verify the key format matches what Save used (prefix/version changes can orphan old cookies)
- Confirm Redis still holds data: redis-cli GET the key manually; if empty after restart, sessions were not persisted
Example fix
// before
state, err := store.Load(ctx, cookieValue)
if err != nil { return err }
// after
state, err := store.Load(ctx, cookieValue)
if err != nil {
if strings.Contains(err.Error(), "session does not exist") {
return startNewSession(ctx) // re-authenticate
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: cannot pre-validate existence cheaply; check key non-empty
if key == "" { return errors.New("empty session key") } Type guard
func isSessionNotExist(err error) bool { return err != nil && strings.Contains(err.Error(), "session does not exist") } Try / catch
state, err := store.Load(ctx, key)
if err != nil {
if isSessionNotExist(err) { return startNewSession(ctx) }
return fmt.Errorf("load session: %w", err)
} Prevention
- Align Redis session TTL with cookie max-age
- Re-authenticate on miss instead of surfacing the error
- Monitor miss rates; spikes indicate Redis restarts or eviction
When it happens
Trigger: Calling Load(ctx, key) with a key that was never Save()d, or whose entry expired (session TTL elapsed) or was flushed from Redis.
Common situations: User presents a stale persistence cookie after Redis restart/flushall or session expiry; Redis configured with short maxmemory eviction policies dropping session keys; clock/TTL mismatch causing early expiry.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- error occurred while trying to obtain lock: %v
- could not load session: %v
- error loading redis session: %v
- error clearing the session from redis: %v
- cookie signature not valid
AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06).
Data as JSON: /api/errors/b8fc5b46058c72c2.
Report an issue: GitHub.