apache/kafka · error · IllegalArgumentException

Topic must be non-null.

Error message

Topic must be non-null.

What it means

IllegalArgumentException thrown by ConsumerRecords.records(String topic) when the topic argument is null. The lookup compares each partition's topic via equals(), so a null topic would never match and is treated as a programming error.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerRecords.java:122

            // every call. A time based approach is used to avoid this. See KAFKA-20660 for more details.
            if (now - lastLog >= TAINT_LOG_INTERVAL_NS && TAINTED_NEXT_OFFSETS_LAST_LOG_NS.compareAndSet(lastLog, now)) {
                log.error("ConsumerRecords#nextOffsets() returned empty because this instance was built with the " +
                        "deprecated ConsumerRecords(Map) constructor (see KIP-1094), which does not supply next offsets. " +
                        "Downstream logic that relies on these offsets to advance the consumer's committed position " +
                        "(for example, Kafka Streams under exactly-once semantics) will be unable to commit, leading to " +
                        "reprocessing. Update the interceptor or wrapper that constructed it to use the " +
                        "ConsumerRecords(Map, Map) constructor that supplies next offsets.");
            }
        }
        return nextOffsets;
    }

    /**
     * Get just the records for the given topic
     */
    public Iterable<ConsumerRecord<K, V>> records(String topic) {
        if (topic == null)
            throw new IllegalArgumentException("Topic must be non-null.");
        List<List<ConsumerRecord<K, V>>> recs = new ArrayList<>();
        for (Map.Entry<TopicPartition, List<ConsumerRecord<K, V>>> entry : records.entrySet()) {
            if (entry.getKey().topic().equals(topic))
                recs.add(entry.getValue());
        }
        return new ConcatenatedIterable<>(recs);
    }

    /**
     * Get the partitions which have records contained in this record set.
     * @return The set of partitions with data in this record set (may be empty if no data was returned)
     */
    public Set<TopicPartition> partitions() {
        return Collections.unmodifiableSet(records.keySet());
    }

    @Override
    public Iterator<ConsumerRecord<K, V>> iterator() {

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Validate the topic variable is non-null before calling records(topic).
  2. Ensure the source feeding the topic name (config, request param, map key) actually contains it.
  3. Default or skip with an explicit empty check: if (topic != null) { for (Record r : cr.records(topic)) ... }.

Example fix

// before
Iterable<ConsumerRecord<K,V>> recs = consumerRecords.records(maybeTopic);

// after
if (maybeTopic == null) throw new IllegalStateException("topic not configured");
Iterable<ConsumerRecord<K,V>> recs = consumerRecords.records(maybeTopic);
Defensive patterns

Strategy: validation

Validate before calling

if (topic == null) {
    throw new IllegalArgumentException("topic must be non-null for ConsumerRecords.records(topic)");
}
Iterable<ConsumerRecord<K,V>> recs = consumerRecords.records(topic);

Try / catch

try {
    consumerRecords.records(topic);
} catch (IllegalArgumentException e) {
    if ("Topic must be non-null.".equals(e.getMessage())) {
        // topic came from external input — default to iterating consumerRecords.partitions() instead
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling consumerRecords.records(topicVar) where topicVar is null; passing a topic sourced from an Optional/Map.get that returned null without a guard.

Common situations: Topic name read from external config that is missing; code branching on a topic string that was never set; loop variables that resolve to null for empty iteration.

Related errors


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