{"id":"9fbbd10393f06b90","repo":"go-redis/redis","slug":"failed-to-enable-maintnotifications-w","errorCode":null,"errorMessage":"failed to enable maintnotifications: %w","messagePattern":"failed to enable maintnotifications: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"redis.go","lineNumber":978,"sourceCode":"\t\t\tif !isRedisError(maintNotifHandshakeErr) {\n\t\t\t\t// if not redis error, fail the connection\n\t\t\t\tcn.GetStateMachine().Transition(pool.StateClosed)\n\t\t\t\treturn maintNotifHandshakeErr\n\t\t\t}\n\t\t\tc.optLock.Lock()\n\t\t\t// handshake failed - check and modify config atomically\n\t\t\tswitch c.opt.MaintNotificationsConfig.Mode {\n\t\t\tcase maintnotifications.ModeEnabled:\n\t\t\t\t// enabled mode, fail the connection\n\t\t\t\tc.optLock.Unlock()\n\t\t\t\tcn.GetStateMachine().Transition(pool.StateClosed)\n\n\t\t\t\t// Record handshake failure metric\n\t\t\t\tif errorCallback := pool.GetMetricErrorCallback(); errorCallback != nil {\n\t\t\t\t\terrorCallback(ctx, \"HANDSHAKE_FAILED\", cn, \"HANDSHAKE_FAILED\", true, 0)\n\t\t\t\t}\n\n\t\t\t\treturn fmt.Errorf(\"failed to enable maintnotifications: %w\", maintNotifHandshakeErr)\n\t\t\tdefault: // will handle auto and any other\n\t\t\t\t// Disabling logging here as it's too noisy.\n\t\t\t\t// TODO: Enable when we have a better logging solution for log levels\n\t\t\t\t// internal.Logger.Printf(ctx, \"auto mode fallback: maintnotifications disabled due to handshake error: %v\", maintNotifHandshakeErr)\n\t\t\t\tc.opt.MaintNotificationsConfig.Mode = maintnotifications.ModeDisabled\n\t\t\t\tc.optLock.Unlock()\n\t\t\t\t// auto mode, disable maintnotifications and continue\n\t\t\t\tif initErr := c.disableMaintNotificationsUpgrades(); initErr != nil {\n\t\t\t\t\t// Log error but continue - auto mode should be resilient\n\t\t\t\t\tinternal.Logger.Printf(ctx, \"failed to disable maintnotifications in auto mode: %v\", initErr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif !c.opt.DisableIdentity && !c.opt.DisableIndentity {\n\t\tlibName := \"\"\n\t\tlibVer := Version()","sourceCodeStart":960,"sourceCodeEnd":996,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/redis.go#L960-L996","documentation":"Thrown when the CLIENT MAINT_NOTIFICATIONS handshake returns a redis-side error and MaintNotificationsConfig.Mode is ModeEnabled. The handshake is attempted after HELLO succeeds (RESP3); a server-side rejection means the server does not support the command, so the client fails the connection closed rather than continuing without notifications.","triggerScenarios":"Options.Protocol = 3, HELLO succeeded, Mode == ModeEnabled, and the server returned a redis error to CLIENT MAINT_NOTIFICATIONS (e.g. ERR unknown command on Redis < 8.8, or search/cluster mode that rejects it). Non-redis errors (transport) fail the connection unconditionally before reaching this branch.","commonSituations":"Server is Redis 6/7 with RESP3 but predates CLIENT MAINT_NOTIFICATIONS (added in 8.8); managed Redis that blocks the command; mode explicitly set to ModeEnabled against an endpoint that does not advertise the feature; mixing a ModeEnabled client with a Redis version that gate-gates the command behind a flag.","solutions":["Use ModeAuto (default) so the client downgrades to disabled on rejection instead of failing the connection.","Upgrade the server to Redis 8.8+ which supports CLIENT MAINT_NOTIFICATIONS, and enable any required feature flags.","If the feature is mandatory for your app, route ModeEnabled clients only to endpoints known to support it.","Inspect the wrapped error text for the exact server rejection (unknown command, disabled, permission)."],"exampleFix":"// before\ncfg := &redis.MaintNotificationsConfig{Mode: redis.ModeEnabled}\nopt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}\n// Redis 7.x rejects CLIENT MAINT_NOTIFICATIONS\n\n// after\ncfg := &redis.MaintNotificationsConfig{Mode: redis.ModeAuto}\nopt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}","handlingStrategy":"validation","validationCode":"// Check CLIENT MAINT_NOTIFICATIONS support before requiring it.\n// Use redis-cli or INFO to confirm Redis >= 8.8.\nif !serverSupportsCommand(ctx, probeClient, \"client|maint_notifications\") {\n    return errors.New(\"server lacks CLIENT MAINT_NOTIFICATIONS\")\n}","typeGuard":null,"tryCatchPattern":"if err := client.Ping(ctx).Err(); err != nil {\n    if strings.Contains(err.Error(), \"failed to enable maintnotifications\") {\n        // server rejected CLIENT MAINT_NOTIFICATIONS; switch to ModeAuto\n    }\n}","preventionTips":["Use ModeAuto in mixed-version fleets so one RESP3-but-old server does not break all connections.","Track the server command list (COMMAND DOCS) during provisioning to verify feature availability.","Reserve ModeEnabled for environments where you control the Redis version."],"tags":["maintnotifications","config","protocol","version-compat"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}