redis/jedis · error · JedisException

Could not enable client tracking. Reply

Error message

Could not enable client tracking. Reply: ${reply}

What it means

After registering the invalidation push consumer, initializeClientSideCache sends CLIENT TRACKING ON and expects a simple status reply of OK. Any other reply (e.g. ERR from a server that rejects or does not support tracking, or a proxy swallowing it) raises this JedisException containing the raw reply. This catches servers that passed the version check but still refused the command.

Solutions

  1. Read the reply text in the exception message and fix the server-side cause (e.g. un-rename/enable the CLIENT command).
  2. Ensure the client connects directly to a Redis 7.4+ node, not through a proxy that strips CLIENT subcommands.
  3. Check server logs for why CLIENT TRACKING was rejected (maxclients, unsupported mode, wrong protocol).
  4. Retry connection establishment if the failure was transient (e.g. failover raced during init).

Example fix

// server side (redis.conf)
// before: rename-command CLIENT ""
// after: remove the rename so CLIENT TRACKING works
# rename-command CLIENT ""   <-- delete this line
Defensive patterns

Strategy: try-catch

Validate before calling

// verify CLIENT TRACKING manually before enabling csc
String reply = jedis.sendCommand(Protocol.Command.CLIENT, "TRACKING", "OFF").getStatusCodeReply();
// ensure reply == OK; ERR indicates tracking is blocked on this server/proxy

Try / catch

try {
  CacheConnection conn = CacheConnection.builder(cache).clientConfig(cfg).build();
} catch (JedisException e) {
  if (e.getMessage().startsWith("Could not enable client tracking")) {
    // fall back to a non-caching connection or alert ops (proxy/renamed CLIENT command)
  } else throw e;
}

Prevention

When it happens

Trigger: CLIENT TRACKING ON returns a non-OK status reply — e.g. server rejects tracking due to maxmemory-policy/proxy interference, command renamed or disabled via rename-command, a proxy in front of Redis not forwarding CLIENT subcommands, or RESP3 push negotiation failing.

Common situations: Deployments behind HAProxy/Twemproxy that filter CLIENT commands; secured clusters where CLIENT is renamed; Redis Enterprise or managed services restricting CLIENT TRACKING; race conditions where the connection is switched to another server mid-init.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/csc/CacheConnection.java:164

  private void initializeClientSideCache() {
    if (getRedisProtocol() != RedisProtocol.RESP3) {
      throw new JedisException("Client side caching is only supported with RESP3.");
    }
    Objects.requireNonNull(cache);
    if (!cache.compatibilityMode()) {
      RedisVersion current = new RedisVersion(version);
      RedisVersion required = new RedisVersion(MIN_REDIS_VERSION);
      if (!REDIS.equals(server) || current.compareTo(required) < 0) {
        throw new JedisException(
          String.format("Client side caching is only supported with 'Redis %s' or later.", MIN_REDIS_VERSION));
      }
    }
    addPushConsumer(new PushInvalidateConsumer(cache));
    sendCommand(Protocol.Command.CLIENT, "TRACKING", "ON");
    String reply = getStatusCodeReply();
    if (!"OK".equals(reply)) {
      throw new JedisException("Could not enable client tracking. Reply: " + reply);
    }
  }

  @SuppressWarnings("rawtypes")
  private CacheEntry validateEntry(CacheEntry cacheEntry) {
    CacheConnection cacheOwner = cacheEntry.getConnection();
    if (cacheOwner == null || cacheOwner.isBroken() || !cacheOwner.isConnected()) {
      cache.delete(cacheEntry.getCacheKey());
      return null;
    } else {
      try {
        cacheOwner.readPushesWithCheckingBroken();
      } catch (JedisException e) {
        cache.delete(cacheEntry.getCacheKey());
        return null;
      }

      return cache.get(cacheEntry.getCacheKey());

View on GitHub (pinned to 6dac31d4c2)