apache/kafka · error · java.lang.IllegalArgumentException

RebalanceListener cannot be null

Error message

RebalanceListener cannot be null

What it means

Thrown by ClassicKafkaConsumer.subscribe(Collection<String>, ConsumerRebalanceListener) as an IllegalArgumentException when the listener argument is null. The classic consumer requires a non-null listener because partition assignment/revocation callbacks are the only way to learn about rebalance events on this API variant, and forwarding null would cause NPEs inside the coordinator during rebalance. The guard fails fast at the call site.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java:442

            return Collections.unmodifiableSet(this.subscriptions.assignedPartitions());
        } finally {
            release();
        }
    }

    public Set<String> subscription() {
        acquireAndEnsureOpen();
        try {
            return Set.copyOf(this.subscriptions.subscription());
        } finally {
            release();
        }
    }

    @Override
    public void subscribe(Collection<String> topics, ConsumerRebalanceListener listener) {
        if (listener == null)
            throw new IllegalArgumentException("RebalanceListener cannot be null");

        subscribeInternal(topics, Optional.of(listener));
    }


    @Override
    public void registerMetricForSubscription(KafkaMetric metric) {
        if (!metrics().containsKey(metric.metricName())) {
            clientTelemetryReporter.ifPresent(reporter -> reporter.metricChange(metric));
        } else {
            log.debug("Skipping registration for metric {}. Existing consumer metrics cannot be overwritten.", metric.metricName());
        }
    }

    @Override
    public void unregisterMetricFromSubscription(KafkaMetric metric) {
        if (!metrics().containsKey(metric.metricName())) {
            clientTelemetryReporter.ifPresent(reporter -> reporter.metricRemoval(metric));

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Pass a real ConsumerRebalanceListener instance, or use the single-argument subscribe(Collection) overload if you do not need callbacks.
  2. Initialize the listener field before subscribe: this.listener = new MyRebalanceListener(); consumer.subscribe(topics, listener);
  3. If the listener is optional in your design, branch: if (listener != null) subscribe(topics, listener); else subscribe(topics);
  4. Add a null-check unit test at the wrapper layer to catch regressions.

Example fix

// before
consumer.subscribe(topics, null);

// after
consumer.subscribe(topics, new ConsumerRebalanceListener() {
    @Override public void onPartitionsRevoked(Collection<TopicPartition> p) {}
    @Override public void onPartitionsAssigned(Collection<TopicPartition> p) {}
});
// or simply: consumer.subscribe(topics);
Defensive patterns

Strategy: validation

Validate before calling

// Provide a no-op listener when you have no rebalance logic, never null.
ConsumerRebalanceListener listener = (realListener != null)
    ? realListener
    : new ConsumerRebalanceListener() {
        @Override public void onPartitionsRevoked(Collection<TopicPartition> p) {}
        @Override public void onPartitionsAssigned(Collection<TopicPartition> p) {}
    };
consumer.subscribe(topics, listener);

Type guard

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

Try / catch

try {
    consumer.subscribe(topics, listener);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("RebalanceListener cannot be null")) {
        consumer.subscribe(topics); // fall back to overload without listener
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling consumer.subscribe(topics, null) using the two-argument Collection overload; passing a listener field that has not been initialized (still null) at the call site; refactoring that moved listener construction after the subscribe call.

Common situations: Refactoring from subscribe(topics) to the listener variant and forgetting to instantiate the listener; conditional listener construction where one branch leaves it null; copy-paste of a code sample that omitted the listener instantiation; testing utilities that pass null for 'no listener' when the no-listener overload should be used instead.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/1bc6e6b73f85818f.json. Report an issue: GitHub.