go-redis/redis · info

shutdown

Error message

shutdown

What it means

Returned by queueHandoff (handoff_worker.go:292,296,306) when the worker manager's shutdown channel is closed — i.e. the maintenance manager is shutting down (Manager.Close) and will not accept new handoff requests. It is a graceful-shutdown sentinel; the affected connection is removed from the pool.

Source

Thrown at maintnotifications/errors.go:59

	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)
)

// circuit breaker configuration errors
var (
	// ErrInvalidCircuitBreakerFailureThreshold is returned when the circuit breaker failure threshold is invalid
	ErrInvalidCircuitBreakerFailureThreshold = errors.New(logs.InvalidCircuitBreakerFailureThresholdError())
	// ErrInvalidCircuitBreakerResetTimeout is returned when the circuit breaker reset timeout is invalid
	ErrInvalidCircuitBreakerResetTimeout = errors.New(logs.InvalidCircuitBreakerResetTimeoutError())
	// ErrInvalidCircuitBreakerMaxRequests is returned when the circuit breaker max requests is invalid
	ErrInvalidCircuitBreakerMaxRequests = errors.New(logs.InvalidCircuitBreakerMaxRequestsError())
)

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Ensure you stop issuing commands (gracefully drain) before calling Close(), so no new handoffs are attempted during teardown.
  2. Treat ErrShutdown during shutdown as expected — log at debug, not error.
  3. Avoid repeatedly creating and closing clients in a hot path; reuse a long-lived client.
  4. If seen outside of an explicit shutdown, check for a double-Close or premature manager teardown.
Defensive patterns

Strategy: try-catch

Try / catch

if errors.Is(err, maintnotifications.ErrShutdown) {
    // expected during client teardown; stop issuing commands and return.
    return err
}

Prevention

When it happens

Trigger: Client.Close() (or Manager shutdown) races with an incoming MOVING notification that tries to queue a handoff. queueHandoff selects on hwm.shutdown first/priority and returns ErrShutdown instead of enqueuing.

Common situations: Application shutdown coinciding with a server-side migration; a health-check/restart loop that tears down clients during cluster events; calling Close() from one goroutine while another is actively serving traffic that triggers maintenance notifications.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/fa3ec2113b45e676.json. Report an issue: GitHub.