{"id":"153dda5e603cee03","repo":"go-redis/redis","slug":"connection-marked-for-handoff-with-state","errorCode":null,"errorMessage":"connection marked for handoff with state","messagePattern":"connection marked for handoff with state","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"maintnotifications/errors.go","lineNumber":51,"sourceCode":"var (\n\t// ErrHandoffQueueFull is returned when the handoff queue is full\n\tErrHandoffQueueFull = errors.New(logs.HandoffQueueFullError())\n)\n\n// Notification errors\nvar (\n\t// ErrInvalidNotification is returned when a notification is in an invalid format\n\tErrInvalidNotification = errors.New(logs.InvalidNotificationError())\n)\n\n// connection handoff errors\nvar (\n\t// ErrConnectionMarkedForHandoff is returned when a connection is marked for handoff\n\t// and should not be used until the handoff is complete\n\tErrConnectionMarkedForHandoff = errors.New(logs.ConnectionMarkedForHandoffErrorMessage)\n\t// ErrConnectionMarkedForHandoffWithState is returned when a connection is marked for handoff\n\t// and should not be used until the handoff is complete\n\tErrConnectionMarkedForHandoffWithState = errors.New(logs.ConnectionMarkedForHandoffErrorMessage + \" with state\")\n\t// ErrConnectionInvalidHandoffState is returned when a connection is in an invalid state for handoff\n\tErrConnectionInvalidHandoffState = errors.New(logs.ConnectionInvalidHandoffStateErrorMessage)\n)\n\n// shutdown errors\nvar (\n\t// ErrShutdown is returned when the maintnotifications manager is shutdown\n\tErrShutdown = errors.New(logs.ShutdownError())\n)\n\n// circuit breaker errors\nvar (\n\t// ErrCircuitBreakerOpen is returned when the circuit breaker is open\n\tErrCircuitBreakerOpen = errors.New(logs.CircuitBreakerOpenErrorMessage)\n)\n\n// circuit breaker configuration errors\nvar (","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/maintnotifications/errors.go#L33-L69","documentation":"Returned by PoolHook.OnGet (pool_hook.go:127) when a pooled connection has ShouldHandoff() == true — it received a MOVING notification and is awaiting relocation, so it must not be handed out for new commands. Like error 50 this is flow control: the pool skips it and selects another connection.","triggerScenarios":"A connection received a MOVING push notification (state set to moving/handoff-pending) but has not yet been queued/processed by a worker; OnGet sees ShouldHandoff() and returns (false, ErrConnectionMarkedForHandoffWithState) so the connection is reserved for handoff rather than reused.","commonSituations":"Normal during migrations — many connections may be marked simultaneously. Becomes visible as a hard error only if the pool is exhausted of unmarked connections (very small PoolSize relative to active handoffs).","solutions":["Raise PoolSize so marked connections don't starve the usable set.","Ensure the handoff worker pool (MaxWorkers) drains marked connections promptly — increase it under heavy migration load.","Treat this sentinel in any custom pool/errgroup wrapper as 'try another connection', not a fatal error.","Verify HandoffQueueSize is large enough that marked connections are queued quickly rather than lingering."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Pool internally retries with another connection. If exposed, retry:\nif errors.Is(err, maintnotifications.ErrConnectionMarkedForHandoffWithState) {\n    return retryCommand(ctx, cmd)\n}","preventionTips":["Size PoolSize and MaxWorkers for concurrent handoff volume.","Treat the sentinel as flow control, not an error, in wrappers.","Keep HandoffQueueSize large so marked connections are relocated fast."],"tags":["maintnotifications","pool","handoff","connection"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}