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.SessionState

View on GitHub (pinned to 33c2eb92de)

Solutions

  1. Treat this as an expected cache miss: re-authenticate the user and Save a fresh session instead of surfacing the error
  2. Check Redis TTL config and session cookie lifetime so they align (cookie outliving the Redis entry causes this)
  3. Verify the key format matches what Save used (prefix/version changes can orphan old cookies)
  4. 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

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


AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06). Data as JSON: /api/errors/b8fc5b46058c72c2. Report an issue: GitHub.