apache/kafka · error · IllegalArgumentException

RebalanceListener cannot be null

Error message

RebalanceListener cannot be null

What it means

Thrown by MockConsumer.subscribe(Pattern, ConsumerRebalanceListener) when the listener argument is null. This overload explicitly takes a listener (unlike the no-listener overloads that pass null internally), and Kafka requires the listener because rebalance callbacks are the whole point of supplying one. If you do not need callbacks, call the single-arg subscribe(Pattern) overload instead.

Solutions

  1. Pass a real ConsumerRebalanceListener (e.g. a no-op stub) when calling the two-arg overload.
  2. If you have no callbacks, switch to the single-arg subscribe(Pattern) overload.
  3. Initialize the listener field before subscribing; assert it is non-null in a @BeforeEach.

Example fix

// before
mockConsumer.subscribe(Pattern.compile("orders-.*"), null);

// after
// option A: no listener needed
mockConsumer.subscribe(Pattern.compile("orders-.*"));
// option B: supply a stub
mockConsumer.subscribe(Pattern.compile("orders-.*"), new ConsumerRebalanceListener() {
    @Override public void onPartitionsRevoked(Collection<TopicPartition> p) {}
    @Override public void onPartitionsAssigned(Collection<TopicPartition> p) {}
});
Defensive patterns

Strategy: validation

Validate before calling

ConsumerRebalanceListener listener = Objects.requireNonNull(listenerArg, "listener");
mockConsumer.subscribe(pattern, listener);

Type guard

static boolean hasListener(ConsumerRebalanceListener l) {
    return l != null;
}

Try / catch

try {
    mockConsumer.subscribe(pattern, listener);
} catch (IllegalArgumentException e) {
    if ("RebalanceListener cannot be null".equals(e.getMessage())) {
        mockConsumer.subscribe(pattern, new NoOpConsumerRebalanceListener()); // or use single-arg overload
    } else throw e;
}

Prevention

When it happens

Trigger: Passing a null rebalance listener to the (Pattern, listener) overload; passing a listener variable that was never initialized; copy-paste from code that conditionally supplies a listener.

Common situations: Tests that subscribe with a stub listener field that defaulted to null; refactor that removed listener initialization but kept the two-arg call.

Related errors


AI-assisted analysis of apache/kafka@996fb4585a (2026-08-11). Data as JSON: /api/errors/088d30e05e3347fa. Report an issue: GitHub.

Appendix: source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/MockConsumer.java:194

            .filter(tp -> !lost.contains(tp))
            .collect(Collectors.toSet());
        this.subscriptions.assignFromSubscribed(remaining);
    }

    @Override
    public synchronized Set<String> subscription() {
        return subscriptions.subscription();
    }

    @Override
    public synchronized void subscribe(Collection<String> topics) {
        subscribeInternal(topics, null);
    }

    @Override
    public synchronized void subscribe(Pattern pattern, final ConsumerRebalanceListener listener) {
        if (listener == null)
            throw new IllegalArgumentException("RebalanceListener cannot be null");

        subscribeInternal(pattern, listener);
    }

    @Override
    public synchronized void subscribe(Pattern pattern) {
        subscribeInternal(pattern, null);
    }

    @Override
    public synchronized void subscribe(SubscriptionPattern pattern, ConsumerRebalanceListener listener) {
        if (listener == null)
            throw new IllegalArgumentException("RebalanceListener cannot be null");

        subscribeInternal(pattern, listener);
    }

    @Override

View on GitHub (pinned to 996fb4585a)