{"id":"639938f3d00d1f33","repo":"go-redis/redis","slug":"redis-connection-not-available","errorCode":null,"errorMessage":"redis: connection not available","messagePattern":"redis: connection not available","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/pool/conn.go","lineNumber":27,"sourceCode":"\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/internal\"\n\t\"github.com/redis/go-redis/v9/internal/maintnotifications/logs\"\n\t\"github.com/redis/go-redis/v9/internal/proto\"\n\tuberatomic \"go.uber.org/atomic\"\n)\n\nvar noDeadline = time.Time{}\n\n// Preallocated errors for hot paths to avoid allocations\nvar (\n\terrAlreadyMarkedForHandoff  = errors.New(\"connection is already marked for handoff\")\n\terrNotMarkedForHandoff      = errors.New(\"connection was not marked for handoff\")\n\terrHandoffStateChanged      = errors.New(\"handoff state changed during marking\")\n\terrConnectionNotAvailable   = errors.New(\"redis: connection not available\")\n\terrConnNotAvailableForWrite = errors.New(\"redis: connection not available for write operation\")\n)\n\n// getCachedTimeNs returns the current time in nanoseconds.\n// This function previously used a global cache updated by a background goroutine,\n// but that caused unnecessary CPU usage when the client was idle (ticker waking up\n// the scheduler every 50ms). We now use time.Now() directly, which is fast enough\n// on modern systems (vDSO on Linux) and only adds ~1-2% overhead in extreme\n// high-concurrency benchmarks while eliminating idle CPU usage.\nfunc getCachedTimeNs() int64 {\n\treturn time.Now().UnixNano()\n}\n\n// GetCachedTimeNs returns the current time in nanoseconds.\n// Exported for use by other packages that need fast time access.\nfunc GetCachedTimeNs() int64 {\n\treturn getCachedTimeNs()\n}","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/internal/pool/conn.go#L9-L45","documentation":"errConnectionNotAvailable is a preallocated hot-path error (conn.go:27) returned by Conn.WithReader and WithReaderHardDeadline when the underlying net.Conn has been removed (nil) from the atomic wrapper. This happens when a connection was concurrently closed, marked for handoff, or torn down by maintenance notifications while a read is in flight. The pool treats it as a bad-conn error and typically retries on a fresh connection.","triggerScenarios":"A read (response read) racing with connection close/handoff in the maintenance-notifications path, or a stale connection being used after Close(). Surfaced via WithReader/WithReaderHardDeadline (conn.go:1041-1062).","commonSituations":"Maintenance window (MIGRATING/FAILING_OVER) on Redis Cloud/Cluster where the connection is handed off mid-operation, or high churn with frequent connection eviction.","solutions":["Let go-redis retry automatically — this error is transient and the cmd will be retried on a new connection for retriable commands.","If surfacing to the caller, retry the operation idempotently.","Ensure maintenance notifications are enabled (Protocol 3, ModeAuto) so handoff is seamless rather than abrupt."],"exampleFix":"// retry on transient connection-unavailable\nfor i := 0; i < 3; i++ {\n    err := client.Get(ctx, key).Err()\n    if err == nil { break }\n    if errors.Is(err, pool.errConnectionNotAvailable) { continue }\n}","handlingStrategy":"retry","validationCode":"// No pre-check possible (concurrent close). Ensure maintnotifications + RESP3 enabled\n// so handoff is seamless rather than abruptly removing the net.Conn.","typeGuard":null,"tryCatchPattern":"for i := 0; i < 3; i++ {\n    if err := client.Get(ctx, key).Err(); err != nil {\n        if isBadConn(err, false) { continue }\n        return err\n    }\n    break\n}","preventionTips":["Enable maintenance notifications (Protocol 3, ModeAuto) for seamless handoff.","Keep MinIdleConns > 0 so replacement connections exist.","Don't hold connections across long blocking calls."],"tags":["pool","connection","transient","maintnotifications","retry"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}