go-redis/redis · error
failed to enable maintnotifications: server does not support
Error message
failed to enable maintnotifications: server does not support RESP3 (HELLO command failed)
What it means
Thrown when maintenance notifications are explicitly required (MaintNotificationsConfig.Mode == ModeEnabled), Protocol is 3, but the HELLO command did not succeed — meaning the connection negotiated RESP2 and cannot receive RESP3 push frames. The client fails the connection fast rather than silently operating without maintenance notifications.
Source
Thrown at redis.go:927
endpointType = c.opt.MaintNotificationsConfig.EndpointType
maintNotifMode = c.opt.MaintNotificationsConfig.Mode
}
c.optLock.RUnlock()
// Maintenance notifications require RESP3 push frames. If HELLO failed
// and the connection fell back to RESP2, there is no point in sending
// CLIENT MAINT_NOTIFICATIONS: the server either rejects it (making the
// error misleading) or accepts it silently, leaving the client unable
// to receive any notifications. Decide based on the actual negotiated
// protocol rather than the requested one.
if maintNotifEnabled && protocol == 3 && !helloOK {
if maintNotifMode == maintnotifications.ModeEnabled {
// Explicitly requested - fail fast with a clear reason.
cn.GetStateMachine().Transition(pool.StateClosed)
if errorCallback := pool.GetMetricErrorCallback(); errorCallback != nil {
errorCallback(ctx, "HANDSHAKE_FAILED", cn, "HANDSHAKE_FAILED", true, 0)
}
return fmt.Errorf("failed to enable maintnotifications: server does not support RESP3 (HELLO command failed)")
}
// auto/other modes: silently disable maintnotifications for this client.
c.optLock.Lock()
c.opt.MaintNotificationsConfig.Mode = maintnotifications.ModeDisabled
c.optLock.Unlock()
if err := c.disableMaintNotificationsUpgrades(); err != nil {
internal.Logger.Printf(ctx, "failed to disable maintnotifications in auto mode: %v", err)
}
maintNotifEnabled = false
}
var maintNotifHandshakeErr error
if maintNotifEnabled && protocol == 3 {
// Hold the manager read lock across the handshake and tracking so a
// concurrent downgrade cannot remove pool-level listeners before a
// successfully enabled connection is tracked for retirement.
c.maintNotificationsManagerLock.RLock()
manager := c.maintNotificationsManagerView on GitHub (pinned to 36d97525cd)
Solutions
- Switch MaintNotificationsConfig.Mode to ModeAuto (default) or ModeDisabled if the endpoint is known to be RESP2-only — the client will then silently disable maintnotifications instead of failing.
- Upgrade the target server to Redis 6+ (preferably 8.x) so HELLO/RESP3 and CLIENT MAINT_NOTIFICATIONS are supported.
- Confirm Options.Protocol is actually 3 and not being overridden; remove any proxy that strips RESP3.
- Validate connectivity to a RESP3-capable endpoint before constructing the client.
Example fix
// before
cfg := &redis.MaintNotificationsConfig{Mode: redis.ModeEnabled}
opt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}
// server is RESP2-only -> connection fails
// after
cfg := &redis.MaintNotificationsConfig{Mode: redis.ModeAuto}
opt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg} Defensive patterns
Strategy: validation
Validate before calling
// Detect RESP3/HELLO support before opting into ModeEnabled.
c := redis.NewClient(&redis.Options{Addr: addr, Protocol: 2})
var info map[string]string
_ = c.Hello(ctx, 3, "", "", "").Scan(&info)
c.Close()
if len(info) == 0 {
return errors.New("server does not support RESP3; use ModeAuto/ModeDisabled")
} Try / catch
defer func() {
if r := recover(); r != nil {
if strings.Contains(fmt.Sprint(r), "does not support RESP3") {
// downgrade config and retry
}
}
}()
client := redis.NewClient(opt) Prevention
- Default to ModeAuto so RESP2-only endpoints silently disable maintnotifications.
- Document the minimum Redis version (6+) for any ModeEnabled deployment.
- Pin REDIS_VERSION in CI to a RESP3-capable image when testing ModeEnabled.
When it happens
Trigger: Options.MaintNotificationsConfig.Mode = ModeEnabled, Options.Protocol = 3, and the server rejects or does not support HELLO (redis < 6, DragonflyDB, a proxy, or RESP2-only endpoint). Returned on every dial since maintnotification handshake is part of initConn.
Common situations: Pointing a ModeEnabled client at an older Redis (< 6) that has no HELLO; pointing at DragonflyDB or a proxy that speaks RESP2; connecting through a RESP2-terminating load balancer; REDIS_VERSION mismatch between configured image and actual server.
Related errors
- invalid client type
- failed to enable maintnotifications: %w
- MaxWorkers must be greater than or equal to 0
- handoff queue size must be greater than 0
- post-handoff relaxed duration must be greater than or equal
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/e98e75eb41ccec46.json.
Report an issue: GitHub.