apache/kafka · error · java.lang.IllegalArgumentException
Topic collection to subscribe to cannot be null
Error message
Topic collection to subscribe to cannot be null
What it means
Thrown by ClassicKafkaConsumer.subscribeInternal as an IllegalArgumentException when the topics collection is null. It mirrors the contract of the async consumer: subscription is defined only for a non-null collection, and a null is treated as a programming error rather than an unsubscribe. The guard fires before any coordinator interaction so the caller sees the mistake immediately.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java:496
* with manual partition assignment through {@link #assign(Collection)}.
*
* If the given list of topics is empty, it is treated the same as {@link #unsubscribe()}.
*
* <p>
* @param topics The list of topics to subscribe to
* @param listener {@link Optional} listener instance to get notifications on partition assignment/revocation
* for the subscribed topics
* @throws IllegalArgumentException If topics is null or contains null or empty elements
* @throws IllegalStateException If {@code subscribe()} is called previously with pattern, or assign is called
* previously (without a subsequent call to {@link #unsubscribe()}), or if not
* configured at-least one partition assignment strategy
*/
private void subscribeInternal(Collection<String> topics, Optional<ConsumerRebalanceListener> listener) {
acquireAndEnsureOpen();
try {
throwIfGroupIdNotDefined();
if (topics == null)
throw new IllegalArgumentException("Topic collection to subscribe to cannot be null");
if (topics.isEmpty()) {
// treat subscribing to empty topic list as the same as unsubscribing
this.unsubscribe();
} else {
for (String topic : topics) {
if (isBlank(topic))
throw new IllegalArgumentException("Topic collection to subscribe to cannot contain null or empty topic");
}
throwIfNoAssignorsConfigured();
// Clear the buffered data which are not a part of newly assigned topics
final Set<TopicPartition> currentTopicPartitions = new HashSet<>();
for (TopicPartition tp : subscriptions.assignedPartitions()) {
if (topics.contains(tp.topic()))
currentTopicPartitions.add(tp);
}View on GitHub (pinned to c31c9215e1)
Solutions
- Pass a non-null collection: consumer.subscribe(Collections.singletonList("orders"));
- Ensure config loaders return an empty list instead of null when no topics are configured, then decide whether to subscribe or unsubscribe based on emptiness.
- Guard at the call site: if (topics != null) consumer.subscribe(topics);
- Add an integration test exercising the subscribe path with a populated list.
Example fix
// before consumer.subscribe((Collection<String>) null); // after List<String> topics = config.topics() != null ? config.topics() : List.of(); if (!topics.isEmpty()) consumer.subscribe(topics); else consumer.unsubscribe();
Defensive patterns
Strategy: validation
Validate before calling
// Identical defence to error 110.
if (topics == null) {
throw new IllegalArgumentException("topics must not be null");
}
consumer.subscribe(topics); Type guard
// Wrap as Optional to force explicit handling.
Optional.ofNullable(topics)
.orElseThrow(() -> new IllegalArgumentException("topics is null"))
.forEach(consumer::subscribe); Try / catch
try {
consumer.subscribe(topics);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("cannot be null")) {
log.warn("Null topics on classic consumer; ignoring subscribe");
} else throw e;
} Prevention
- Default topic collections to empty List rather than null.
- Centralize subscribe calls behind one wrapper that enforces non-null.
- Static-analysis rule: @NonNull on method parameters feeding subscribe().
When it happens
Trigger: Calling consumer.subscribe((Collection<String>) null) on a ClassicKafkaConsumer; frameworks (Spring Kafka, Quarkus) that forward a nullable topic list into the classic consumer; reflection-based wiring where the topic list field is still null at subscribe time.
Common situations: Topic list loaded lazily and not yet populated when subscribe is called; DI container ordering; config-driven topic lists where the config key is missing and the loader returns null instead of an empty list; migration between assign() (which has different null semantics) and subscribe().
Related errors
- Topic collection to subscribe to cannot be null
- RebalanceListener cannot be null
- Topic collection to subscribe to cannot contain null or empt
- Topic collection to subscribe to cannot contain null or empt
- The configured group.id should not be an empty string or whi
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/43b8a7d6571f31e3.json.
Report an issue: GitHub.