redisson/redisson · error · UnsupportedOperationException
Subscribe through ReactiveSubscription object created by cre
Error message
Subscribe through ReactiveSubscription object created by createSubscription method
What it means
Redisson's implementation of the Spring Data Redis reactive API deliberately does not support the one-shot subscribe(ByteBuffer...) method on ReactiveRedisConnection.ReactivePubSubCommands. Subscription state (channels, patterns, listeners) must live in a ReactiveSubscription object, because Redisson routes pub/sub messages through its own connection manager event loop. Calling subscribe directly would create state Redisson cannot track, so it throws UnsupportedOperationException to redirect you to createSubscription().
Source
Thrown at redisson-spring/redisson-spring-data/redisson-spring-data-25/src/main/java/org/redisson/spring/data/connection/RedissonReactivePubSubCommands.java:56
RedissonReactivePubSubCommands(CommandReactiveExecutor executorService) {
super(executorService);
}
@Override
public Mono<ReactiveSubscription> createSubscription() {
return Mono.just(new RedissonReactiveSubscription(executorService.getConnectionManager()));
}
@Override
public Flux<Long> publish(Publisher<ChannelMessage<ByteBuffer, ByteBuffer>> messageStream) {
return execute(messageStream, msg -> {
return write(toByteArray(msg.getChannel()), StringCodec.INSTANCE, RedisCommands.PUBLISH, toByteArray(msg.getChannel()), toByteArray(msg.getMessage()));
});
}
@Override
public Mono<Void> subscribe(ByteBuffer... channels) {
throw new UnsupportedOperationException("Subscribe through ReactiveSubscription object created by createSubscription method");
}
@Override
public Mono<Void> pSubscribe(ByteBuffer... patterns) {
throw new UnsupportedOperationException("Subscribe through ReactiveSubscription object created by createSubscription method");
}
}
View on GitHub (pinned to 91188987c2)
Solutions
- Call createSubscription() to get a RedissonReactiveSubscription, then call subscribe(channels) on that object
- Register listeners via subscription.receive() / receiveLater() before subscribing so messages are not missed
- Keep a reference to the subscription and close it (subscription.close()) when done, since channels stay subscribed until then
Example fix
// before
Flux<ByteBuffer> msgs = connection.pubSubCommands()
.subscribe(ByteBuffer.wrap("channel".getBytes())) // throws
.thenMany(Flux.empty());
// after
ReactiveRedisConnection.ReactiveSubscription sub =
connection.pubSubCommands().createSubscription();
Flux<ByteBufferMessage> msgs = sub.receive()
.doOnSubscribe(s -> sub.subscribe(ByteBuffer.wrap("channel".getBytes())).subscribe());
// ... and on shutdown:
sub.close(); Defensive patterns
Strategy: validation
Validate before calling
// Before subscribing, obtain the subscription object — never call the
// one-shot subscribe on ReactivePubSubCommands:
ReactiveRedisConnection.ReactiveSubscription sub =
connection.pubSubCommands().createSubscription();
if (sub != null) {
sub.receive().doOnNext(this::onMessage).subscribe();
sub.subscribe(ByteBuffer.wrap(channel.getBytes())).subscribe();
} Try / catch
try {
connection.pubSubCommands().subscribe(channels); // unsupported
} catch (UnsupportedOperationException e) {
// fall back to subscription-object API
ReactiveRedisConnection.ReactiveSubscription sub =
connection.pubSubCommands().createSubscription();
sub.receive().doOnNext(this::onMessage).subscribe();
sub.subscribe(channels).subscribe();
} Prevention
- Treat createSubscription() as the only entry point for reactive pub/sub in Redisson
- Store the ReactiveSubscription in a field and close it on bean destruction to avoid leaked subscriptions
- Add an integration test that exercises your subscribe path so the UnsupportedOperationException is caught in CI, not production
When it happens
Trigger: Calling RedissonReactivePubSubCommands.subscribe(channels) directly, e.g. connection.pubSubCommands().subscribe(ByteBuffer.wrap("ch".getBytes())). Also hit when application code or a framework adapter calls the ReactivePubSubCommands interface method instead of obtaining a subscription object.
Common situations: Migrating from Lettuce/Jedis reactive adapters to Redisson where subscribe() on the commands object used to work; test code that exercises the ReactivePubSubCommands interface directly; higher-level code that assumes all ReactivePubSubCommands methods are implemented.
Related errors
- Subscribe through ReactiveSubscription object created by cre
- Subscribe through ReactiveSubscription object created by cre
- NOT operation doesn't support more than single source key
- Connection already subscribed
- Should be defined through Redisson Config object
AI-assisted analysis of redisson/redisson@91188987c2 (2026-08-14).
Data as JSON: /api/errors/73302e7813a5a406.
Report an issue: GitHub.