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
- Configure the client to use RESP3 so maintenance push frames can be processed.
- Disable strict mode for the maintenance visitor if notifications should be skipped with a log line instead of an exception.
- Verify the endpoint actually supports RESP3; fix proxies that force RESP2.
- 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
- Always configure RESP3 when maintenance-aware endpoints are targeted.
- Verify endpoint/proxy protocol negotiation supports RESP3.
- Set strict=false for the visitor if notifications are optional in your environment.
- Add a configuration smoke test validating protocol + endpoint combination.
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
- Blocking pub/sub operations are not supported on…
- Unsupported protocol:
- Client-side caching is only supported with RESP3.
- Client-side caching is only supported with RESP3.
- Jedis does not support RESP3 protocol auto-negotiation…
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)