redis/jedis · critical · IllegalStateException

HELLO response is missing the protocol version field

Error message

HELLO response is missing the protocol version field

What it means

After the HELLO handshake, Connection verifies that the server-reported HELLO map contained a protocol version field, from which the negotiated RedisProtocol is derived. A null protocol means the server's HELLO reply was malformed or unexpectedly shaped, so an IllegalStateException is thrown to prevent running with an unknown protocol.

Solutions

  1. Verify the endpoint is a real Redis server >= 6.0 that answers HELLO fully (run HELLO manually via redis-cli)
  2. Bypass or reconfigure the proxy so HELLO replies are passed through unmodified
  3. Force RESP2 (protocol 2) in the client config so HELLO negotiation is avoided if the server/proxy cannot handle it
  4. Check server version compatibility and upgrade Redis or the middleware

Example fix

// before
JedisClient c = RedisClient.builder()
    .hostAndPort(proxyHost, 6379) // proxy drops HELLO protover
    .build();
// after
JedisClient c = RedisClient.builder()
    .hostAndPort(redisHost, 6379) // real Redis, or
    .protocol(RedisProtocol.RESP2) // skip HELLO negotiation
    .build();
Defensive patterns

Strategy: try-catch

Validate before calling

// before connecting: verify endpoint
// redis-cli -h host -p port HELLO  -> must include a 'proto' field

Try / catch

try { client = RedisClient.builder().hostAndPort(h, p).build(); } catch (JedisConnectionException | IllegalStateException e) { log.error("HELLO handshake incomplete; check server/proxy", e); }

Prevention

When it happens

Trigger: Connecting to an endpoint that returns an incomplete HELLO reply — e.g. a proxy/middleware (Envoy, Twemproxy-like layers) stripping fields, a fake/mock Redis server, or a non-Redis service on the port.

Common situations: Pointing Jedis at a proxy or TLS-terminating middlebox that mangles RESP3 HELLO; connecting to an incompatible or mock server in tests; unusual/old server builds replying to HELLO without the protover field.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/Connection.java:1004

   *          {@code autoNegotiateProtocol}
   * @param autoNegotiateProtocol whether to attempt {@code HELLO 3} with RESP2 fallback when no
   *          protocol is explicitly requested; ignored when {@code requestedProtocol} is
   *          non-{@code null}
   * @param credentials credentials used for authentication (may be {@code null})
   * @throws IllegalArgumentException if the requested protocol is not supported
   * @throws IllegalStateException if the server's HELLO response is missing the protocol field
   * @throws JedisProtocolNotSupportedException if protocol negotiation fails
   * @throws JedisDataException if the server returns an error during handshake
   */
  private void establishProtocol(final RedisProtocol requestedProtocol,
      final boolean autoNegotiateProtocol, final RedisCredentials credentials) {
    HelloResult helloResult = handshake.establish(requestedProtocol, autoNegotiateProtocol,
      credentials);
    version = helloResult.getVersion();
    server = helloResult.getServer();

    if (helloResult.getProtocol() == null) {
      throw new IllegalStateException("HELLO response is missing the protocol version field");
    }

    this.protocol = helloResult.getProtocol();
  }

  public void setCredentials(RedisCredentials credentials) {
    currentCredentials.set(credentials);
  }

  String authenticate(RedisCredentials credentials) {
    if (credentials == null || credentials.getPassword() == null) {
      return null;
    }
    byte[] rawPass = encodeToBytes(credentials.getPassword());
    try {
      if (credentials.getUser() == null) {
        sendCommand(Command.AUTH, rawPass);
      } else {

View on GitHub (pinned to 6dac31d4c2)