redis/jedis · error · JedisConnectionException

Unexpected character!

Error message

Unexpected character!

What it means

RedisInputStream.ensureCrLf consumes bytes after a CR until it finds the LF that terminates a CRLF reply line. If the byte following \r is not \n, the reply stream is malformed, so the parser aborts with a JedisConnectionException. This indicates a corrupted or non-RESP stream between client and server.

Solutions

  1. Close and reopen the connection (return it to the pool as broken / destroy it) — the stream offset is unrecoverable.
  2. Verify no intermediate proxy or firewall is altering the Redis protocol stream.
  3. Confirm the endpoint is actually a Redis server speaking RESP2/RESP3.
  4. Upgrade Jedis to ensure you are on a version compatible with your server's RESP protocol version.

Example fix

// before
try {
  String val = jedis.get(key);
} catch (JedisConnectionException e) {
  // connection kept in pool with corrupt stream
}
// after
try {
  String val = jedis.get(key);
} catch (JedisConnectionException e) {
  jedis.close(); // or pool.returnBrokenResource(jedis)
  val = jedisRetry.get(key);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (connectionDesyncSuspected) { throw new IllegalStateException("discard connection before reuse"); }

Try / catch

try {
  return jedis.get(key);
} catch (JedisConnectionException e) {
  jedis.close(); // return broken resource
  return retryOnFreshConnection(() -> jedisPool.getResource().get(key));
}

Prevention

When it happens

Trigger: Thrown from ensureCrLf (called by readNullCrLf and readBooleanCrLf) when the byte after '\r' is not '\n' while parsing a bulk-string null reply or a boolean reply.

Common situations: A proxy, TLS terminator, or middlebox mangling the RESP stream; reading from a socket that is not speaking RESP; a desynchronized connection reused after a prior parse failure.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/util/RedisInputStream.java:71

  public byte readByte() throws JedisConnectionException {
    ensureFill();
    return buf[count++];
  }

  private void ensureCrLf() {
    final byte[] buf = this.buf;

    ensureFill();
    if (buf[count++] == '\r') {

      ensureFill();
      if (buf[count++] == '\n') {
        return;
      }
    }

    throw new JedisConnectionException("Unexpected character!");
  }

  public String readLine() {
    final StringBuilder sb = new StringBuilder();
    while (true) {
      ensureFill();

      byte b = buf[count++];
      if (b == '\r') {
        ensureFill(); // Must be one more byte

        byte c = buf[count++];
        if (c == '\n') {
          break;
        }
        sb.append((char) b);
        sb.append((char) c);
      } else {

View on GitHub (pinned to 6dac31d4c2)