{"id":"e98e75eb41ccec46","repo":"go-redis/redis","slug":"failed-to-enable-maintnotifications-server-does-n","errorCode":null,"errorMessage":"failed to enable maintnotifications: server does not support RESP3 (HELLO command failed)","messagePattern":"failed to enable maintnotifications: server does not support RESP3 \\(HELLO command failed\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"redis.go","lineNumber":927,"sourceCode":"\t\tendpointType = c.opt.MaintNotificationsConfig.EndpointType\n\t\tmaintNotifMode = c.opt.MaintNotificationsConfig.Mode\n\t}\n\tc.optLock.RUnlock()\n\n\t// Maintenance notifications require RESP3 push frames. If HELLO failed\n\t// and the connection fell back to RESP2, there is no point in sending\n\t// CLIENT MAINT_NOTIFICATIONS: the server either rejects it (making the\n\t// error misleading) or accepts it silently, leaving the client unable\n\t// to receive any notifications. Decide based on the actual negotiated\n\t// protocol rather than the requested one.\n\tif maintNotifEnabled && protocol == 3 && !helloOK {\n\t\tif maintNotifMode == maintnotifications.ModeEnabled {\n\t\t\t// Explicitly requested - fail fast with a clear reason.\n\t\t\tcn.GetStateMachine().Transition(pool.StateClosed)\n\t\t\tif errorCallback := pool.GetMetricErrorCallback(); errorCallback != nil {\n\t\t\t\terrorCallback(ctx, \"HANDSHAKE_FAILED\", cn, \"HANDSHAKE_FAILED\", true, 0)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to enable maintnotifications: server does not support RESP3 (HELLO command failed)\")\n\t\t}\n\t\t// auto/other modes: silently disable maintnotifications for this client.\n\t\tc.optLock.Lock()\n\t\tc.opt.MaintNotificationsConfig.Mode = maintnotifications.ModeDisabled\n\t\tc.optLock.Unlock()\n\t\tif err := c.disableMaintNotificationsUpgrades(); err != nil {\n\t\t\tinternal.Logger.Printf(ctx, \"failed to disable maintnotifications in auto mode: %v\", err)\n\t\t}\n\t\tmaintNotifEnabled = false\n\t}\n\n\tvar maintNotifHandshakeErr error\n\tif maintNotifEnabled && protocol == 3 {\n\t\t// Hold the manager read lock across the handshake and tracking so a\n\t\t// concurrent downgrade cannot remove pool-level listeners before a\n\t\t// successfully enabled connection is tracked for retirement.\n\t\tc.maintNotificationsManagerLock.RLock()\n\t\tmanager := c.maintNotificationsManager","sourceCodeStart":909,"sourceCodeEnd":945,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/redis.go#L909-L945","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncfg := &redis.MaintNotificationsConfig{Mode: redis.ModeEnabled}\nopt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}\n// server is RESP2-only -> connection fails\n\n// after\ncfg := &redis.MaintNotificationsConfig{Mode: redis.ModeAuto}\nopt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}","handlingStrategy":"validation","validationCode":"// Detect RESP3/HELLO support before opting into ModeEnabled.\nc := redis.NewClient(&redis.Options{Addr: addr, Protocol: 2})\nvar info map[string]string\n_ = c.Hello(ctx, 3, \"\", \"\", \"\").Scan(&info)\nc.Close()\nif len(info) == 0 {\n    return errors.New(\"server does not support RESP3; use ModeAuto/ModeDisabled\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if strings.Contains(fmt.Sprint(r), \"does not support RESP3\") {\n            // downgrade config and retry\n        }\n    }\n}()\nclient := redis.NewClient(opt)","preventionTips":["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."],"tags":["maintnotifications","resp3","config","protocol"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}