{"id":"737245173df19619","repo":"apache/kafka","slug":"topic-collection-to-subscribe-to-cannot-be-null","errorCode":null,"errorMessage":"Topic collection to subscribe to cannot be null","messagePattern":"Topic collection to subscribe to cannot be null","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java","lineNumber":2297,"sourceCode":"            release();\n        }\n    }\n\n    private void throwIfSubscriptionPatternIsInvalid(SubscriptionPattern subscriptionPattern) {\n        if (subscriptionPattern == null) {\n            throw new IllegalArgumentException(\"Topic pattern to subscribe to cannot be null\");\n        }\n        if (subscriptionPattern.pattern().isEmpty()) {\n            throw new IllegalArgumentException(\"Topic pattern to subscribe to cannot be empty\");\n        }\n    }\n\n    private void subscribeInternal(Collection<String> topics, Optional<ConsumerRebalanceListener> listener) {\n        acquireAndEnsureOpen();\n        try {\n            throwIfGroupIdNotDefined();\n            if (topics == null)\n                throw new IllegalArgumentException(\"Topic collection to subscribe to cannot be null\");\n            if (topics.isEmpty()) {\n                // treat subscribing to empty topic list as the same as unsubscribing\n                unsubscribe();\n            } else {\n                for (String topic : topics) {\n                    if (isBlank(topic))\n                        throw new IllegalArgumentException(\"Topic collection to subscribe to cannot contain null or empty topic\");\n                }\n\n                // Clear the buffered data which are not a part of newly assigned topics\n                final Set<TopicPartition> currentTopicPartitions = new HashSet<>();\n\n                for (TopicPartition tp : subscriptions.assignedPartitions()) {\n                    if (topics.contains(tp.topic()))\n                        currentTopicPartitions.add(tp);\n                }\n\n                fetchBuffer.retainAll(currentTopicPartitions);","sourceCodeStart":2279,"sourceCodeEnd":2315,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java#L2279-L2315","documentation":"Thrown by AsyncKafkaConsumer.subscribeInternal as an IllegalArgumentException when the topics argument is null. The async consumer refuses a null collection before it can enter the background event pipeline, because there is no meaningful subscription event to enqueue. It is a fast-fail guard that mirrors the classic consumer's contract so caller bugs surface at the API boundary rather than as NPEs on the network thread.","triggerScenarios":"Calling consumer.subscribe((Collection<String>) null) or subscribe((Collection<String>) null, listener) on an AsyncKafkaConsumer instance; also triggered indirectly by frameworks that forward a nullable topic list (e.g. Spring Kafka's ContainerProperties when topic list is unset) into the new KIP-848 async consumer.","commonSituations":"Migrating to the async consumer (group.protocol=consumer) where a previously-tolerated null is now guarded; reflection/dependency-injection wiring that has not yet resolved the topic list at construction time; copy-paste from assign() code paths where null is handled differently.","solutions":["Initialize the topic collection before calling subscribe, e.g. pass Collections.singletonList(\"my-topic\") or an explicitly built Set<String>.","If the topic list is genuinely optional, guard the call site: if (topics != null && !topics.isEmpty()) consumer.subscribe(topics); else consumer.unsubscribe();","Audit framework adapters (Spring Kafka, Micronaut Kafka) that bridge into KafkaConsumer to ensure they never forward a null collection.","Add a unit test asserting subscribe(null) throws IllegalArgumentException so regressions are caught at the boundary."],"exampleFix":"// before\nconsumer.subscribe((Collection<String>) null);\n\n// after\nconsumer.subscribe(Collections.singletonList(\"orders\"));","handlingStrategy":"validation","validationCode":"// Before consumer.subscribe(topics):\nif (topics == null) {\n    throw new IllegalArgumentException(\"topics must not be null\");\n}\n// or normalize: Collection<String> safe = (topics == null) ? List.of() : topics;","typeGuard":"// Java has no null-narrowing; guard at call site.\n// Optional<Collection<String>> nonNullTopics = Optional.ofNullable(topics);\n// nonNullTopics.ifPresent(consumer::subscribe);","tryCatchPattern":"// Safety net only; prefer pre-validation.\ntry {\n    consumer.subscribe(topics);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"cannot be null\")) {\n        log.warn(\"subscribe called with null topics; skipping\");\n    } else {\n        throw e;\n    }\n}","preventionTips":["Initialize topic collections as List.of() / new ArrayList<>() at declaration so they are never null by default.","Run consumer.subscribe() inside a thin wrapper that null-checks its argument.","Enable static analysis (SpotBugs NP_NONNULL_* / IntelliJ @NotNull annotations) to flag null collections at compile time.","Treat empty collection as unsubscribe (Kafka supports it); only null is an error."],"tags":["kafka","consumer","async-consumer","subscribe","validation","argument"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}