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
- Verify the endpoint is a real Redis server >= 6.0 that answers HELLO fully (run HELLO manually via redis-cli)
- Bypass or reconfigure the proxy so HELLO replies are passed through unmodified
- Force RESP2 (protocol 2) in the client config so HELLO negotiation is avoided if the server/proxy cannot handle it
- 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
- Confirm HELLO works via redis-cli before wiring the client
- Avoid proxies that rewrite RESP handshake traffic
- Force RESP2 for older servers or constrained middleboxes
- Keep Redis >= 6.0 for HELLO/RESP3 support
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
- binary ft.search is not implemented with resp3.
- Unsupported protocol:
- Client-side caching is only supported with RESP3.
- Client-side caching is only supported with RESP3.
- Range must not be null.
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)