go-redis/redis · error

failed to enable maintnotifications: %w

Error message

failed to enable maintnotifications: %w

What it means

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.

Source

Thrown at redis.go:978

			if !isRedisError(maintNotifHandshakeErr) {
				// if not redis error, fail the connection
				cn.GetStateMachine().Transition(pool.StateClosed)
				return maintNotifHandshakeErr
			}
			c.optLock.Lock()
			// handshake failed - check and modify config atomically
			switch c.opt.MaintNotificationsConfig.Mode {
			case maintnotifications.ModeEnabled:
				// enabled mode, fail the connection
				c.optLock.Unlock()
				cn.GetStateMachine().Transition(pool.StateClosed)

				// Record handshake failure metric
				if errorCallback := pool.GetMetricErrorCallback(); errorCallback != nil {
					errorCallback(ctx, "HANDSHAKE_FAILED", cn, "HANDSHAKE_FAILED", true, 0)
				}

				return fmt.Errorf("failed to enable maintnotifications: %w", maintNotifHandshakeErr)
			default: // will handle auto and any other
				// Disabling logging here as it's too noisy.
				// TODO: Enable when we have a better logging solution for log levels
				// internal.Logger.Printf(ctx, "auto mode fallback: maintnotifications disabled due to handshake error: %v", maintNotifHandshakeErr)
				c.opt.MaintNotificationsConfig.Mode = maintnotifications.ModeDisabled
				c.optLock.Unlock()
				// auto mode, disable maintnotifications and continue
				if initErr := c.disableMaintNotificationsUpgrades(); initErr != nil {
					// Log error but continue - auto mode should be resilient
					internal.Logger.Printf(ctx, "failed to disable maintnotifications in auto mode: %v", initErr)
				}
			}
		}
	}

	if !c.opt.DisableIdentity && !c.opt.DisableIndentity {
		libName := ""
		libVer := Version()

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Use ModeAuto (default) so the client downgrades to disabled on rejection instead of failing the connection.
  2. Upgrade the server to Redis 8.8+ which supports CLIENT MAINT_NOTIFICATIONS, and enable any required feature flags.
  3. If the feature is mandatory for your app, route ModeEnabled clients only to endpoints known to support it.
  4. Inspect the wrapped error text for the exact server rejection (unknown command, disabled, permission).

Example fix

// before
cfg := &redis.MaintNotificationsConfig{Mode: redis.ModeEnabled}
opt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}
// Redis 7.x rejects CLIENT MAINT_NOTIFICATIONS

// after
cfg := &redis.MaintNotificationsConfig{Mode: redis.ModeAuto}
opt := &redis.Options{Addr: addr, Protocol: 3, MaintNotificationsConfig: cfg}
Defensive patterns

Strategy: validation

Validate before calling

// Check CLIENT MAINT_NOTIFICATIONS support before requiring it.
// Use redis-cli or INFO to confirm Redis >= 8.8.
if !serverSupportsCommand(ctx, probeClient, "client|maint_notifications") {
    return errors.New("server lacks CLIENT MAINT_NOTIFICATIONS")
}

Try / catch

if err := client.Ping(ctx).Err(); err != nil {
    if strings.Contains(err.Error(), "failed to enable maintnotifications") {
        // server rejected CLIENT MAINT_NOTIFICATIONS; switch to ModeAuto
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/9fbbd10393f06b90.json. Report an issue: GitHub.