{"record":{"id":"1ff3c88dd3542eb5","repo":"redis/jedis","slug":"maintenance-notifications","errorCode":null,"errorMessage":"Maintenance notifications: ","messagePattern":"Maintenance notifications: ","errorType":"exception","errorClass":"JedisConnectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/MaintenanceAwareVisitor.java","lineNumber":76,"sourceCode":"\n  @Override\n  public void visitAfterHandshake(Connection connection) {\n    MaintenanceNotificationsConfig mConfig = builder.getMaintenanceConfig();\n    if (!isMaintenanceEnabled(mConfig)) {\n      return;\n    }\n\n    boolean strict = mConfig.getMode() == MaintenanceNotificationsConfig.Mode.ENABLED;\n    boolean keepOverrides = false;\n\n    try {\n      // Maintenance push frames require RESP3.\n      RedisProtocol protocol = connection.getRedisProtocol();\n      if (protocol != RedisProtocol.RESP3) {\n        String reason = \"RESP3 is required but the established protocol is \"\n            + (protocol == null ? \"RESP2\" : protocol);\n        if (strict) {\n          throw new JedisConnectionException(\"Maintenance notifications: \" + reason);\n        }\n        logger.debug(\"Maintenance notifications disabled: {}.\", reason);\n        return;\n      }\n\n      Set<MaintenanceEventListener> maintenanceEventListeners = connection\n          .getMaintenanceEventListeners();\n      maintenanceEventListeners.add(controller);\n\n      // The server must accept CLIENT MAINT_NOTIFICATIONS ON. Pre-register the consumer so a\n      // push\n      // frame the server emits immediately on accepting the subscription cannot race ahead.\n      MaintenanceEventConsumer consumer = new MaintenanceEventConsumer(connection,\n          maintenanceEventListeners);\n      connection.addPushConsumer(consumer);\n\n      connection.sendCommand(Command.CLIENT, \"MAINT_NOTIFICATIONS\", \"ON\", \"moving-endpoint-type\",\n        resolveEndpointType(connection, mConfig));","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/MaintenanceAwareVisitor.java#L58-L94","documentation":"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\").","triggerScenarios":"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.","commonSituations":"Using RESP2 against Redis Enterprise/managed endpoints that issue maintenance push frames; explicit protocol(RedisProtocol.RESP2) configuration; endpoints behind proxies that downgrade the protocol.","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."],"exampleFix":"// before\nRedisClient client = RedisClient.builder()\n    .protocol(RedisProtocol.RESP2)\n    .maintenanceAware(true) // strict visitor -> JedisConnectionException\n    .build();\n// after\nRedisClient client = RedisClient.builder()\n    .protocol(RedisProtocol.RESP3)\n    .maintenanceAware(true)\n    .build();","handlingStrategy":"validation","validationCode":"if (client.getConfig().getProtocol() != RedisProtocol.RESP3\n    && maintenanceAwarenessEnabled) {\n  throw new IllegalStateException(\"Maintenance awareness requires RESP3\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  client = builder.build();\n} catch (JedisConnectionException e) {\n  if (e.getMessage().startsWith(\"Maintenance notifications\")) {\n    // switch protocol to RESP3 or disable strict maintenance handling\n  } else throw e;\n}","preventionTips":["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."],"tags":["resp3","maintenance-notifications","configuration"],"backgroundTag":"invalid-config-value","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}