{"record":{"id":"28ad6db22e97598b","repo":"apache/pulsar","slug":"bindaddresses-conflicting-listener-names-for-ad","errorCode":null,"errorMessage":"bindAddresses: conflicting listener names for ${address}: `${existingListener}` and `${listener}`","messagePattern":"bindAddresses: conflicting listener names for (.+?): `(.+?)` and `(.+?)`","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/validator/BindAddressValidator.java","lineNumber":103,"sourceCode":"\n        // apply the filter\n        if (schemes != null) {\n            addresses.removeIf(a -> !schemes.contains(a.getAddress().getScheme()));\n        }\n\n        // Deduplicate by full URI (scheme + ip + port). Tolerate exact duplicates (same URI and\n        // same listener name) so that a user's bindAddresses entry that matches a migrated binding\n        // is accepted; reject same URI assigned to different listener names.\n        Map<URI, BindAddress> uniqueBindAddresses = new LinkedHashMap<>();\n        for (BindAddress addr : addresses) {\n            BindAddress existing = uniqueBindAddresses.get(addr.getAddress());\n            if (existing == null) {\n                uniqueBindAddresses.put(addr.getAddress(), addr);\n            } else if (Objects.equals(existing.getListenerName(), addr.getListenerName())) {\n                // exact duplicate, tolerate\n                continue;\n            } else {\n                throw new IllegalArgumentException(\"bindAddresses: conflicting listener names for \"\n                        + addr.getAddress() + \": `\" + existing.getListenerName() + \"` and `\"\n                        + addr.getListenerName() + \"`\");\n            }\n        }\n\n        // ip:port uniqueness across protocol schemes. A TCP socket can only be bound by one\n        // listener+scheme combination, so two bindings that share host:port but differ in scheme\n        // (e.g. pulsar://0.0.0.0:8080 and http://0.0.0.0:8080) cannot both be active. Port 0 is\n        // skipped because it means \"OS-assigned ephemeral port\" — the kernel will hand out a unique\n        // port to each socket, so two port-0 entries with the same IP cannot actually collide.\n        Map<String, BindAddress> uniqueIpPort = new LinkedHashMap<>();\n        for (BindAddress addr : uniqueBindAddresses.values()) {\n            if (addr.getAddress().getPort() == 0) {\n                continue;\n            }\n            String ipPort = MultipleListenerValidator.formatHostPort(addr.getAddress());\n            BindAddress prior = uniqueIpPort.putIfAbsent(ipPort, addr);\n            if (prior != null) {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/validator/BindAddressValidator.java#L85-L121","documentation":"IllegalArgumentException thrown by BindAddressValidator.validateBindAddresses when two bindAddresses entries resolve to the same ip:port but declare different listener names. Exact duplicates (same address and same listener name) are tolerated, but a shared socket bound under two distinct listener names is ambiguous, so validation fails. This prevents one socket from being reachable under conflicting listener identities.","triggerScenarios":"bindAddresses containing e.g. a:pulsar://10.0.0.1:6650 and b:pulsar://10.0.0.1:6650 — same host:port, different listener names. Wildcard/0.0.0.0 entries can also collide with specific-interface entries mapping to the same resolved address.","commonSituations":"Copy-pasting a listener entry to create a second listener but forgetting to change host or port; DNS names resolving to the same IP with different listener names; container/k8s configs where 0.0.0.0 and an explicit pod IP both appear.","solutions":["Give each ip:port a single listener name — deduplicate or drop the conflicting entry","If two names were intended, bind them to different ports/hosts","Verify resolved addresses (DNS) to spot accidental same-IP collisions","Keep an exact duplicate only if the listener names match (that case is tolerated)"],"exampleFix":"// before\nbindAddresses=a:pulsar://10.0.0.1:6650,b:pulsar://10.0.0.1:6650\n// after\nbindAddresses=a:pulsar://10.0.0.1:6650,b:pulsar://10.0.0.2:6650","handlingStrategy":"validation","validationCode":"Map<String,String> byIpPort = new HashMap<>();\nfor (String s : bindAddresses.split(\",\")) {\n    URI u = URI.create(s.substring(s.indexOf(':') + 1));\n    String key = u.getHost() + \":\" + u.getPort();\n    String name = s.substring(0, s.indexOf(':'));\n    String prev = byIpPort.put(key, name);\n    if (prev != null && !prev.equals(name)) {\n        throw new IllegalArgumentException(\"Conflicting listener names for \" + key + \": \" + prev + \" vs \" + name);\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One listener name per ip:port — dedupe before deploy","Account for DNS names that resolve to the same IP","Beware 0.0.0.0 colliding with explicit interface addresses","Document the intended listener/port matrix in your deployment repo"],"tags":["configuration","bind-address","port-conflict","multi-listener"],"backgroundTag":"address-already-in-use","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"}