go-redis/redis · info
connection marked for handoff
Error message
connection marked for handoff
What it means
Returned by PoolHook.OnGet (pool_hook.go:133) when a pooled connection is not IsUsable() — typically because it is mid-handoff, being re-authenticated, or otherwise in an UNUSABLE/CLOSED state. It signals the pool to skip this connection and pick another; it is a normal flow-control signal during maintenance, not necessarily a caller-visible failure.
Source
Thrown at maintnotifications/errors.go:48
) // Handoff errors var ( // ErrHandoffQueueFull is returned when the handoff queue is full ErrHandoffQueueFull = errors.New(logs.HandoffQueueFullError()) ) // Notification errors var ( // ErrInvalidNotification is returned when a notification is in an invalid format ErrInvalidNotification = errors.New(logs.InvalidNotificationError()) ) // connection handoff errors var ( // ErrConnectionMarkedForHandoff is returned when a connection is marked for handoff // and should not be used until the handoff is complete ErrConnectionMarkedForHandoff = errors.New(logs.ConnectionMarkedForHandoffErrorMessage) // ErrConnectionMarkedForHandoffWithState is returned when a connection is marked for handoff // and should not be used until the handoff is complete ErrConnectionMarkedForHandoffWithState = errors.New(logs.ConnectionMarkedForHandoffErrorMessage + " with state") // ErrConnectionInvalidHandoffState is returned when a connection is in an invalid state for handoff ErrConnectionInvalidHandoffState = errors.New(logs.ConnectionInvalidHandoffStateErrorMessage) ) // shutdown errors var ( // ErrShutdown is returned when the maintnotifications manager is shutdown ErrShutdown = errors.New(logs.ShutdownError()) ) // circuit breaker errors var ( // ErrCircuitBreakerOpen is returned when the circuit breaker is open ErrCircuitBreakerOpen = errors.New(logs.CircuitBreakerOpenErrorMessage) )
View on GitHub (pinned to 36d97525cd)
Solutions
- Increase PoolSize so the pool has enough usable connections during handoff churn.
- Confirm MaxHandoffRetries/HandoffTimeout aren't leaving connections stuck unusable for long.
- If your pool wrapper surfaces OnGet errors directly to callers, translate this sentinel into a retry-on-another-connection rather than a hard failure.
- Check for an unhealthy upstream causing repeated re-auth or handoff (circuit breaker stats).
Defensive patterns
Strategy: retry
Try / catch
// This is normally handled inside the pool (it picks another conn).
// If surfacing from a custom hook wrapper, retry the command:
if errors.Is(err, maintnotifications.ErrConnectionMarkedForHandoff) {
return retryCommand(ctx, cmd)
} Prevention
- Raise PoolSize so unusable connections don't exhaust the pool.
- In custom pool wrappers, treat this sentinel as 'pick another connection', not fatal.
- Monitor how long connections stay unusable.
When it happens
Trigger: The pool's Get path calls OnGet; a connection that was previously returned to the pool is now unusable (a handoff worker is actively relocating it, or it was marked closed). OnGet returns (false, ErrConnectionMarkedForHandoff) so the pool retries with a different connection.
Common situations: Transient during a live migration/failover; can surface as an error to the application only if most/all connections in the pool are simultaneously unusable (small PoolSize during a storm).
Related errors
- connection marked for handoff with state
- redis: connection not available
- redis: connection not available for write operation
- redis: timed out trying to mark connection as unusable
- MaxWorkers must be greater than or equal to 0
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/5e4cb47460c0148e.json.
Report an issue: GitHub.