redis/jedis · error · JedisException

Unknown message type

Error message

Unknown message type: <reply>

What it means

JedisPubSubBase.process() reads replies from the subscription loop and dispatches them by message type (subscribe ack, message, pong, etc.). When a reply arrives that does not match any known pub/sub reply shape, it throws JedisException("Unknown message type: " + reply). It means the connection delivered an object the pub/sub state machine cannot interpret, usually a stray non-pub/sub reply on the subscription connection.

Solutions

  1. Use a dedicated, freshly-obtained connection for pub/sub — never one with outstanding commands or unread replies.
  2. Ensure subscribe/psubscribe is the first command issued on the pub/sub connection.
  3. Check protocol version (RESP2 vs RESP3) matches what the pub/sub implementation expects.
  4. Catch JedisException, close and re-create the subscription connection.

Example fix

// before
Jedis j = pool.getResource();
j.set("k","v");          // reply still pending
new JedisPubSubBase(j).proceed(channel); // desync -> Unknown message type
// after
try (Jedis j = pool.getResource()) {
  j.set("k","v");        // complete within try so reply consumed
}
try (Jedis j = pool.getResource()) {
  new JedisPubSubBase(j).proceed(channel); // clean connection
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (jedis.isSubscribed() || jedis.isBroken()) { jedis.close(); jedis = pool.getResource(); }

Type guard

boolean isPubSubReply(Object reply) {
  return reply instanceof List && !((List<?>) reply).isEmpty()
      && ((List<?>) reply).get(0) instanceof byte[];
}

Try / catch

try {
  pubSub.proceed(jedis, channel);
} catch (JedisException e) {
  if (e.getMessage().startsWith("Unknown message type")) {
    jedis.close();
    // re-subscribe on a fresh connection
  } else throw e;
}

Prevention

When it happens

Trigger: Calling proceed()/proceedWithPatterns() on a connection whose reply stream contains a plain (non-array) object that is not a recognized pub/sub reply type, e.g. a plain byte[] status reply when no resultHandler is registered (that path is checked elsewhere) or a List whose first element is not a known command name byte[].

Common situations: Reusing a Jedis connection for subscribe while a pending command reply (e.g. AUTH or SELECT ack) is still unread; mixing a shared/pipelined connection into pub/sub; protocol desync after an error mid-handshake.

Related errors


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

Appendix: source

Thrown at src/main/java/redis/clients/jedis/JedisPubSubBase.java:198

          subscribedChannels = ((Long) listReply.get(2)).intValue();
          final byte[] bpattern = (byte[]) listReply.get(1);
          final T enpattern = (bpattern == null) ? null : encode(bpattern);
          onPUnsubscribe(enpattern, subscribedChannels);
        } else if (Arrays.equals(PONG.getRaw(), resp)) {
          final byte[] bpattern = (byte[]) listReply.get(1);
          final T enpattern = (bpattern == null) ? null : encode(bpattern);
          onPong(enpattern);
        } else {
          throw new JedisException("Unknown message type: " + firstObj);
        }
      } else if (reply instanceof byte[]) {
        Consumer<Object> resultHandler = authenticator.resultHandler.poll();
        if (resultHandler == null) {
          throw new JedisException("Unexpected message : " + SafeEncoder.encode((byte[]) reply));
        }
        resultHandler.accept(reply);
      } else {
        throw new JedisException("Unknown message type: " + reply);
      }
    } while (!Thread.currentThread().isInterrupted() && isSubscribed());

    //    /* Invalidate instance since this thread is no longer listening */
    //    this.client = null;
  }

  private void processPingReply(Object reply) {
    byte[] resp = (byte[]) reply;
    if ("PONG".equals(SafeEncoder.encode(resp))) {
      onPong(null);
    } else {
      onPong(encode(resp));
    }
  }
}

View on GitHub (pinned to 6dac31d4c2)