redis/jedis · error · JedisException
Blocking pub/sub operations are not supported on…
Error message
Blocking pub/sub operations are not supported on token-based authentication enabled connections with RESP2 protocol!
What it means
With RESP2 there is no push-type notification, so token-based (ACL credential/credential-provider) authentication that needs re-authentication via client tracking/refresh cannot run concurrently with blocking pub/sub reads; a blocked subscribe loop would prevent token renewal and the connection could be revoked mid-stream. Jedis deliberately rejects the combination: subscribe/psubscribe on a connection that both uses token-based authentication and negotiates RESP2 throws this JedisException from checkConnectionSuitableForPubSub (JedisPubSubBase.java:65).
Solutions
- Set protocol RESP3 in the client config: config.protocol(RedisProtocol.RESP3), which supports push messages alongside token auth.
- Disable token-based authentication on the subscribing connection (use static password) if RESP2 must be kept.
- Use a separate connection/client for pub/sub with non-token (static) credentials.
Example fix
// before
JedisClientConfig config = new DefaultJedisClientConfig.Builder()
.credentialProvider(provider)
.build(); // RESP2 default -> throws on subscribe
// after
JedisClientConfig config = new DefaultJedisClientConfig.Builder()
.credentialProvider(provider)
.protocol(RedisProtocol.RESP3)
.build(); Defensive patterns
Strategy: validation
Validate before calling
if (clientConfig.getCredentialProvider() != null
&& clientConfig.getRedisProtocol() != RedisProtocol.RESP3) {
// switch to RESP3 or use static credentials before subscribing
} Try / catch
try {
pubSub.subscribe(jedis, channel);
} catch (JedisException e) {
if (e.getMessage().contains("token-based authentication")) {
jedis = openConnectionWithResp3(config.protocol(RedisProtocol.RESP3));
pubSub.subscribe(jedis, channel);
}
} Prevention
- Always set protocol RESP3 when using token-based/credential-provider auth.
- Keep pub/sub on dedicated connections with explicit, minimal config.
- Document the RESP2 + token-auth incompatibility in team setup guides for Redis 6+ ACLs.
When it happens
Trigger: Calling subscribe(), psubscribe() (or the lazySubscribe equivalents) on a connection whose JedisClientConfig enables token-based authentication (e.g. CredentialProvider with renewal) while the protocol is RESP2 (protocol default or explicitly set to ProtocolVersion.RESP2).
Common situations: Using Redis 6 ACL credentials with a credential provider on default RESP2 protocol; forgetting to set .protocol(RedisProtocol.RESP3) in the client config when token-based auth is on, then subscribing to channels.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unknown message type
- Unexpected message
- Failed to evict connections from pool
- setHostAndPort method has limited capability.
- Unknown message type
AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08).
Data as JSON: /api/errors/a9ac67b6f7696535.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/redis/clients/jedis/JedisPubSubBase.java:65
public final void unsubscribe(T... channels) {
sendAndFlushCommand(Command.UNSUBSCRIBE, channels);
}
public final void subscribe(T... channels) {
checkConnectionSuitableForPubSub();
sendAndFlushCommand(Command.SUBSCRIBE, channels);
}
public final void psubscribe(T... patterns) {
checkConnectionSuitableForPubSub();
sendAndFlushCommand(Command.PSUBSCRIBE, patterns);
}
private void checkConnectionSuitableForPubSub() {
if (authenticator.client.getRedisProtocol() != RedisProtocol.RESP3
&& authenticator.client.isTokenBasedAuthenticationEnabled()) {
throw new JedisException(
"Blocking pub/sub operations are not supported on token-based authentication enabled connections with RESP2 protocol!");
}
}
public final void punsubscribe() {
sendAndFlushCommand(Command.PUNSUBSCRIBE);
}
public final void punsubscribe(T... patterns) {
sendAndFlushCommand(Command.PUNSUBSCRIBE, patterns);
}
public final void ping() {
authenticator.commandSync.lock();
try {
sendAndFlushCommand(Command.PING);
authenticator.resultHandler.add(pingResultHandler);
} finally {View on GitHub (pinned to 6dac31d4c2)