{"record":{"id":"db920b7b7d3c288e","repo":"apache/pulsar","slug":"topicnames-needs-to-be-1","errorCode":null,"errorMessage":"topicNames needs to be = 1","messagePattern":"topicNames needs to be = 1","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java","lineNumber":180,"sourceCode":"    private long autoUpdatePartitionsIntervalSeconds = 60;\n\n    private transient List<ReaderInterceptor<T>> readerInterceptorList;\n\n    // max pending chunked message to avoid sending incomplete message into the queue and memory\n    private int maxPendingChunkedMessage = 10;\n\n    private boolean autoAckOldestChunkedMessageOnQueueFull = false;\n\n    private long expireTimeOfIncompleteChunkedMessageMillis = TimeUnit.MINUTES.toMillis(1);\n\n    private SubscriptionMode subscriptionMode = SubscriptionMode.NonDurable;\n\n    private SubscriptionInitialPosition subscriptionInitialPosition = SubscriptionInitialPosition.Latest;\n\n    @JsonIgnore\n    public String getTopicName() {\n        if (topicNames.size() > 1) {\n            throw new IllegalArgumentException(\"topicNames needs to be = 1\");\n        }\n        return topicNames.iterator().next();\n    }\n\n    @JsonIgnore\n    public void setTopicName(String topicNames) {\n        //Compatible with a single topic\n        this.topicNames.clear();\n        this.topicNames.add(topicNames);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public ReaderConfigurationData<T> clone() {\n        try {\n            ReaderConfigurationData<T> clone = (ReaderConfigurationData<T>) super.clone();\n            clone.setTopicNames(new HashSet<>(clone.getTopicNames()));\n            return clone;\n        } catch (CloneNotSupportedException e) {","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ReaderConfigurationData.java#L162-L198","documentation":"ReaderConfigurationData.getTopicName() returns the single topic a reader is bound to, and throws this IllegalArgumentException if topicNames contains more than one entry. Readers are single-topic constructs, so multi-topic configuration is invalid.","triggerScenarios":"Setting more than one topic via ReaderBuilder.topics(...) or ReaderConfigurationData.setTopicNames(...) and then calling getTopicName() (directly or through ReaderImpl.createReaderAsync / the topic() accessor).","commonSituations":"Reusing a multi-topic consumer configuration object to create a reader; programmatically adding topics to a reader config; copying consumer topic lists into reader configs in test harnesses or migration code.","solutions":["Ensure topicNames contains exactly one topic before creating a Reader.","Use ConsumerBuilder with subscriptionType Exclusive/subscription name instead of a Reader when multiple topics are needed.","Call getTopicNames() and validate size == 1 before calling getTopicName().","If reusing shared config, build a fresh ReaderConfigurationData with a single topic."],"exampleFix":"// before\nReaderConfigurationData<byte[]> conf = new ReaderConfigurationData<>();\nconf.setTopicNames(Sets.newHashSet(\"t1\", \"t2\"));\nString topic = conf.getTopicName(); // throws\n// after\nconf.setTopicNames(Sets.newHashSet(\"t1\"));\nString topic = conf.getTopicName();","handlingStrategy":"validation","validationCode":"if (readerConf.getTopicNames() == null || readerConf.getTopicNames().size() != 1) {\n  throw new IllegalArgumentException(\"Reader requires exactly one topic, got: \" + (readerConf.getTopicNames() == null ? 0 : readerConf.getTopicNames().size()));\n}","typeGuard":"boolean isSingleTopic(ReaderConfigurationData<?> c) { return c.getTopicNames() != null && c.getTopicNames().size() == 1; }","tryCatchPattern":"try { String t = conf.getTopicName(); } catch (IllegalArgumentException e) { /* fall back to consumer-based multi-topic subscription */ }","preventionTips":["Always create readers from a dedicated single-topic ReaderConfigurationData.","Use ConsumerBuilder for multi-topic consumption instead of Reader.","Validate topicNames size before handing config to createReader."],"tags":["reader","configuration","argument-validation","single-topic"],"backgroundTag":"invalid-argument","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}