apache/kafka · error · java.lang.IllegalArgumentException

Topic collection to subscribe to cannot contain null or empt

Error message

Topic collection to subscribe to cannot contain null or empty topic

What it means

Thrown by AsyncKafkaConsumer.subscribeInternal when at least one element of the topics collection is null, empty, or whitespace (via isBlank). The async consumer validates every topic name before enqueuing a TopicSubscriptionChangeEvent, because the background thread cannot report a malformed topic back to the caller cleanly. It is the per-element counterpart to the null-collection guard.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java:2304

        }
        if (subscriptionPattern.pattern().isEmpty()) {
            throw new IllegalArgumentException("Topic pattern to subscribe to cannot be empty");
        }
    }

    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
                unsubscribe();
            } else {
                for (String topic : topics) {
                    if (isBlank(topic))
                        throw new IllegalArgumentException("Topic collection to subscribe to cannot contain null or empty topic");
                }

                // 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);
                }

                fetchBuffer.retainAll(currentTopicPartitions);
                log.info("Subscribed to topic(s): {}", String.join(", ", topics));
                applicationEventHandler.addAndGet(new TopicSubscriptionChangeEvent(
                    new HashSet<>(topics),
                    listener,
                    defaultApiTimeoutDeadlineMs()
                ));
            }

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Sanitize the topic list before subscribe: topics.removeIf(s -> s == null || s.trim().isEmpty()); and log what was dropped.
  2. Fix the source of the list: trim each token when splitting the config string, e.g. Arrays.stream(raw.split(",")).map(String::trim).filter(s -> !s.isEmpty()).collect(toList()).
  3. Validate at application startup and fail fast with a clear error naming the offending topic name.
  4. Add a test for the sanitized list to prevent regressions.

Example fix

// before
String raw = config.get("topics"); // "orders,,payments"
consumer.subscribe(Arrays.asList(raw.split(",")));

// after
List<String> topics = Arrays.stream(raw.split(","))
    .map(String::trim)
    .filter(s -> !s.isEmpty())
    .collect(Collectors.toList());
consumer.subscribe(topics);
Defensive patterns

Strategy: validation

Validate before calling

// Strip blanks before subscribing.
Collection<String> clean = topics == null
    ? List.of()
    : topics.stream()
           .filter(t -> t != null && !t.trim().isEmpty())
           .collect(Collectors.toList());
if (!topics.isEmpty() && clean.isEmpty()) {
    throw new IllegalArgumentException("All provided topics were null/blank");
}
consumer.subscribe(clean);

Type guard

// Predicate-based element guard.
static boolean hasNoBlankTopics(Collection<String> topics) {
    return topics != null && topics.stream().allMatch(t -> t != null && !t.trim().isEmpty());
}

Try / catch

try {
    consumer.subscribe(topics);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("null or empty topic")) {
        topics.removeIf(t -> t == null || t.trim().isEmpty());
        consumer.subscribe(topics); // retry with cleaned set
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling consumer.subscribe(Arrays.asList("orders", "", "payments")), consumer.subscribe(Arrays.asList("orders", null)), or passing a collection that contains a whitespace-only string like " ". Also hit when topic names are read from a config file with trailing empty lines split into list entries.

Common situations: Parsing topics from a comma-separated config property where an empty token slips through (e.g. "orders,,payments"); deserializing a JSON/YAML list that includes nulls; environment-variable overrides that resolve to an empty string in one slot; copy-paste of topic lists with a dangling comma.

Related errors


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