redis/jedis · error · IllegalArgumentException

Client-side caching is only supported with RESP3.

Error message

Client-side caching is only supported with RESP3.

What it means

Client-side caching (RedisPROTOCOL-dependent server-assisted invalidation) requires RESP3, because it relies on push messages. Constructing a UnifiedJedis-derived client with both a Cache configured and RESP2 protocol throws IllegalArgumentException immediately.

Solutions

  1. Set the protocol to RESP3 in the ClientConfig: clientConfig.protocol(RedisProtocol.RESP3).
  2. Ensure the Redis server is v6+ and speaks RESP3.
  3. If RESP2 is mandatory, remove the cache from the configuration.

Example fix

// before
ClientConfig cfg = new ClientConfig().protocol(RedisProtocol.RESP2);
RedisClient c = RedisClient.builder().clientConfig(cfg).cache(new CachedRedisClient.Cache()).build();
// after
ClientConfig cfg = new ClientConfig().protocol(RedisProtocol.RESP3);
RedisClient c = RedisClient.builder().clientConfig(cfg).cache(new Caches.cache()).build();
Defensive patterns

Strategy: validation

Validate before calling

if (cache != null && (protocol == null || protocol == RedisProtocol.RESP2)) {
  throw new IllegalArgumentException("cache requires RESP3");
}

Try / catch

try {
  RedisClient c = RedisClient.builder().clientConfig(cfg).cache(cache).build();
} catch (IllegalArgumentException e) {
  log.error("CSC requires RESP3: {}", e.getMessage());
}

Prevention

When it happens

Trigger: new RedisClient(...)/builder with .cache(...) while protocol is RESP2 or defaulted to RESP2; e.g. clientConfig.protocol(RedisProtocol.RESP2) plus a Cache instance.

Common situations: Upgrading an old RESP2-based config to add client-side caching; copying a cache example without setting RESP3; protocol defaulting to RESP2 in legacy config code paths.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/UnifiedJedis.java:144

    // RESP2 or RESP3 on the wire. Probe a connection to learn the actual value so the command
    // objects parse replies with the correct decoder. If the probe fails or the connection has
    // not yet negotiated, fall back to RESP2 — matching the wire default and preserving lazy
    // construction semantics.
    RedisProtocol resolvedProtocol = protocol;
    if (resolvedProtocol == null && provider != null) {
      try (Connection conn = provider.getConnection()) {
        if (conn != null) {
          resolvedProtocol = conn.getRedisProtocol();
        }
      } catch (JedisException ignored) {
      }
    }
    if (resolvedProtocol == null) {
      resolvedProtocol = RedisProtocol.RESP2;
    }

    if (cache != null && resolvedProtocol != RedisProtocol.RESP3) {
      throw new IllegalArgumentException("Client-side caching is only supported with RESP3.");
    }

    this.commandObjects = newCommandObjects(resolvedProtocol);
    applyCommandObjectsConfiguration(commandObjects, clientConfig);
    this.cache = cache;
  }

  /**
   * Factory hook for the {@link CommandObjects} instance held by this client. Subclasses (e.g.
   * {@link JedisCluster}) override to return their specialized subtype. Called from the
   * {@link UnifiedJedis} constructor — must not depend on subclass instance state.
   */
  protected CommandObjects newCommandObjects(RedisProtocol protocol) {
    return new CommandObjects(protocol);
  }

  /**
   * Applies the {@code CommandObjects}-level knobs ({@code commandKeyArgumentPreProcessor},

View on GitHub (pinned to 6dac31d4c2)