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

  1. Call createSubscription() to get a RedissonReactiveSubscription, then call subscribe(channels) on that object
  2. Register listeners via subscription.receive() / receiveLater() before subscribing so messages are not missed
  3. 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

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


AI-assisted analysis of redisson/redisson@91188987c2 (2026-08-14). Data as JSON: /api/errors/73302e7813a5a406. Report an issue: GitHub.