oauth2-proxy/oauth2-proxy · warning
timeout obtaining session lock
Error message
timeout obtaining session lock
What it means
refreshSessionIfNeeded in pkg/middleware/stored_session.go obtains a session lock (to safely refresh a session near expiry) with a bounded wait of sessionRefreshObtainTimeout. If the lock is not obtained before the context deadline, the loop's ctx.Done() branch returns this error. It prevents concurrent requests from deadlocking on the same session.
Source
Thrown at pkg/middleware/stored_session.go:168
}
// refreshSessionIfNeeded will attempt to refresh a session if the session
// is older than the refresh period.
// Success or fail, we will then validate the session.
func (s *storedSessionLoader) refreshSessionIfNeeded(rw http.ResponseWriter, req *http.Request, session *sessionsapi.SessionState) error {
if !needsRefresh(s.refreshPeriod, session) {
// Refresh is disabled or the session is not old enough, do nothing
return nil
}
var lockObtained bool
ctx, cancel := context.WithTimeout(context.Background(), sessionRefreshObtainTimeout)
defer cancel()
for !lockObtained {
select {
case <-ctx.Done():
return errors.New("timeout obtaining session lock")
default:
err := session.ObtainLock(req.Context(), sessionRefreshLockDuration)
if err != nil && !errors.Is(err, sessionsapi.ErrLockNotObtained) {
return fmt.Errorf("error occurred while trying to obtain lock: %v", err)
} else if errors.Is(err, sessionsapi.ErrLockNotObtained) {
time.Sleep(sessionRefreshRetryPeriod)
continue
}
// No error means we obtained the lock
lockObtained = true
}
}
// The rest of this function is carried out under lock, but we must release it
// wherever we exit from this function.
defer func() {
if session == nil {
returnView on GitHub (pinned to 33c2eb92de)
Solutions
- Tune sessionRefreshObtainTimeout/sessionRefreshRetryPeriod to tolerate expected lock contention
- Check the session store (e.g. Redis) for stale locks left by crashed requests and clear them
- Retry the request after the lock holder completes; the error is transient by design
- Investigate duplicate concurrent refreshes (polling clients) that create lock storms
Defensive patterns
Strategy: retry
Validate before calling
// before issuing a request that will trigger refresh, check remaining lock headroom
if sessionRefreshObtainTimeout < sessionRefreshRetryPeriod {
return errors.New("obtain timeout shorter than retry period")
} Try / catch
session, err := getValidatedSession(req)
if err != nil {
if strings.Contains(err.Error(), "timeout obtaining session lock") {
// transient: back off and retry once
time.Sleep(time.Second)
return getValidatedSession(req)
}
return err
} Prevention
- Size sessionRefreshObtainTimeout larger than the longest expected lock holder
- Clean up stale locks in the session store (e.g. Redis TTL on lock keys)
- Avoid request patterns that refresh the same session concurrently (long polling + refresh on expiry)
- Monitor lock-not-obtained retries as a contention signal
When it happens
Trigger: Another request holds the session lock (session.ObtainLock keeps returning ErrLockNotObtained) for longer than sessionRefreshObtainTimeout while this request tries to refresh a session near its expiry.
Common situations: Long-running upstream request holding the lock while a parallel tab/polling request needs refresh; stuck lock in the session store after a crashed request; very short sessionRefreshObtainTimeout under load.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- session no longer exists, it may have been removed by anothe
- session is expired
- could not read cookie secret file
- no configuration file provided
- secret source is invalid: exactly one entry required, specif
AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06).
Data as JSON: /api/errors/7d198d583cb9f413.
Report an issue: GitHub.