redis/jedis · error · JedisConnectionException

Maintenance notifications:

Error message

Maintenance notifications: 

What it means

MaintenanceAwareVisitor.visitAfterHandshake() inspects maintenance/refresh push notifications that Redis (e.g. managed endpoints doing endpoint migrations) sends after handshake. These require RESP3; if the connection negotiated a different protocol and strict mode is on, it throws JedisConnectionException("Maintenance notifications: RESP3 is required but the established protocol is RESP2").

Solutions

  1. Configure the client to use RESP3 so maintenance push frames can be processed.
  2. Disable strict mode for the maintenance visitor if notifications should be skipped with a log line instead of an exception.
  3. Verify the endpoint actually supports RESP3; fix proxies that force RESP2.
  4. If maintenance notifications are not needed, disable the maintenance-event feature in client config.

Example fix

// before
RedisClient client = RedisClient.builder()
    .protocol(RedisProtocol.RESP2)
    .maintenanceAware(true) // strict visitor -> JedisConnectionException
    .build();
// after
RedisClient client = RedisClient.builder()
    .protocol(RedisProtocol.RESP3)
    .maintenanceAware(true)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

if (client.getConfig().getProtocol() != RedisProtocol.RESP3
    && maintenanceAwarenessEnabled) {
  throw new IllegalStateException("Maintenance awareness requires RESP3");
}

Try / catch

try {
  client = builder.build();
} catch (JedisConnectionException e) {
  if (e.getMessage().startsWith("Maintenance notifications")) {
    // switch protocol to RESP3 or disable strict maintenance handling
  } else throw e;
}

Prevention

When it happens

Trigger: Connecting to a server/endpoint with maintenance-event awareness enabled while the negotiated protocol is RESP2 (or unset, treated as RESP2) and the visitor runs in strict mode.

Common situations: Using RESP2 against Redis Enterprise/managed endpoints that issue maintenance push frames; explicit protocol(RedisProtocol.RESP2) configuration; endpoints behind proxies that downgrade the protocol.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08). Data as JSON: /api/errors/1ff3c88dd3542eb5. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/MaintenanceAwareVisitor.java:76

  @Override
  public void visitAfterHandshake(Connection connection) {
    MaintenanceNotificationsConfig mConfig = builder.getMaintenanceConfig();
    if (!isMaintenanceEnabled(mConfig)) {
      return;
    }

    boolean strict = mConfig.getMode() == MaintenanceNotificationsConfig.Mode.ENABLED;
    boolean keepOverrides = false;

    try {
      // Maintenance push frames require RESP3.
      RedisProtocol protocol = connection.getRedisProtocol();
      if (protocol != RedisProtocol.RESP3) {
        String reason = "RESP3 is required but the established protocol is "
            + (protocol == null ? "RESP2" : protocol);
        if (strict) {
          throw new JedisConnectionException("Maintenance notifications: " + reason);
        }
        logger.debug("Maintenance notifications disabled: {}.", reason);
        return;
      }

      Set<MaintenanceEventListener> maintenanceEventListeners = connection
          .getMaintenanceEventListeners();
      maintenanceEventListeners.add(controller);

      // The server must accept CLIENT MAINT_NOTIFICATIONS ON. Pre-register the consumer so a
      // push
      // frame the server emits immediately on accepting the subscription cannot race ahead.
      MaintenanceEventConsumer consumer = new MaintenanceEventConsumer(connection,
          maintenanceEventListeners);
      connection.addPushConsumer(consumer);

      connection.sendCommand(Command.CLIENT, "MAINT_NOTIFICATIONS", "ON", "moving-endpoint-type",
        resolveEndpointType(connection, mConfig));

View on GitHub (pinned to 6dac31d4c2)