{"record":{"id":"20b3a67afd3dbc5a","repo":"apache/pulsar","slug":"failed-to-bind-pulsar-proxy-on-port-serviceport","errorCode":null,"errorMessage":"Failed to bind Pulsar Proxy on port ${servicePort}","messagePattern":"Failed to bind Pulsar Proxy on port (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyService.java","lineNumber":356,"sourceCode":"            // brokerClientPurpose=true: this lookup transport reuses tlsFactoryClassName to carry the\n            // brokerClientTlsFactoryClassName selection, so a custom by-name factory is wrapped to resolve the\n            // transport's CLIENT_DEFAULT request under the fixed BROKER_CLIENT purpose (matches the direct path\n            // above, which requests BROKER_CLIENT).\n            this.lookupClientTlsFactory = ClientTlsFactorySupport.resolveClientTlsFactory(\n                    lookupClientConf, statsExecutor, statsExecutor, openTelemetry.getOpenTelemetry(), true);\n        }\n\n        bootstrap.childHandler(new ServiceChannelInitializer(this, proxyConfig, false, null));\n        // Bind and start to accept incoming connections.\n        if (proxyConfig.getServicePort().isPresent()) {\n            try {\n                listenChannel = bootstrap.bind(proxyConfig.getBindAddress(),\n                        proxyConfig.getServicePort().get()).sync().channel();\n                log.info()\n                        .attr(\"localAddress\", listenChannel.localAddress())\n                        .log(\"Started Pulsar Proxy at\");\n            } catch (Exception e) {\n                throw new IOException(\"Failed to bind Pulsar Proxy on port \" + proxyConfig.getServicePort().get(), e);\n            }\n        }\n\n        if (proxyConfig.getServicePortTls().isPresent()) {\n            this.sslContextRefresher = Executors\n                    .newSingleThreadScheduledExecutor(\n                            new DefaultThreadFactory(\"proxy-ssl-context-refresher\"));\n            ServerBootstrap tlsBootstrap = bootstrap.clone();\n            this.tlsServiceChannelInitializer = new ServiceChannelInitializer(this, proxyConfig, true,\n                    sslContextRefresher);\n            tlsBootstrap.childHandler(this.tlsServiceChannelInitializer);\n            listenChannelTls = tlsBootstrap.bind(proxyConfig.getBindAddress(),\n                    proxyConfig.getServicePortTls().get()).sync().channel();\n            log.info()\n                    .attr(\"localAddress\", listenChannelTls.localAddress())\n                    .log(\"Started Pulsar TLS Proxy on\");\n        }\n","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyService.java#L338-L374","documentation":"ProxyService.start attempts to bind a Netty ServerBootstrap to the configured servicePort. If the bind (or the sync wait) throws — port already in use, insufficient privileges, or the port is not present in config — it wraps the cause in an IOException with the concrete port so the operator knows which listener failed. The proxy cannot serve clients without this listener, so startup aborts.","triggerScenarios":"Calling proxyService.start() and the bootstrap.bind(bindAddress, servicePort) inside the try block throws, typically BindException: Address already in use because another Pulsar proxy or process holds the port, or servicePort is absent from config (Optional.get() on an empty port), or binding to a privileged port (<1024) without permissions.","commonSituations":"Running two proxy instances on the same host (test environment left running in background); another service occupying the default port 6650; container port collisions in Kubernetes with multiple replicas on one node; missing servicePort entry after config refactoring; IPv6/IPv4 bind-address mismatch.","solutions":["Check what occupies the port (e.g. ss -ltnp or netstat) and stop the conflicting process, or change servicePort in the proxy config to a free port","Ensure servicePort is present and valid in ProxyConfiguration; note bind() is only attempted when servicePort is present","Verify the bindAddress configured for the proxy resolves to a local interface and you have permission to bind (root/CAP_NET_BIND_SERVICE for ports <1024)","In containers, fix duplicate port mappings/hostPort conflicts so only one process binds the port"],"exampleFix":"// before (proxy.conf)\nservicePort=6650  # already held by another proxy\n\n// after\nservicePort=6651","handlingStrategy":"validation","validationCode":"int port = proxyConfig.getServicePort().orElseThrow(\n    () -> new IllegalArgumentException(\"servicePort is required\"));\ntry (ServerSocket ss = new ServerSocket()) {\n    ss.bind(new InetSocketAddress(proxyConfig.getBindAddress(), port));\n} catch (IOException e) {\n    throw new IllegalStateException(\"Port \" + port + \" unavailable before proxy start: \" + e.getMessage());\n}","typeGuard":"boolean servicePortConfigured(ProxyConfiguration cfg) {\n    return cfg.getServicePort().isPresent();\n}","tryCatchPattern":"try {\n    proxyService.start();\n} catch (IOException e) {\n    if (e.getCause() instanceof BindException) {\n        LOG.error(\"Port {} in use; stop the conflicting process or change servicePort\",\n            proxyConfig.getServicePort());\n    }\n    throw e;\n}","preventionTips":["Check port availability with ss -ltnp before starting the proxy","Give each proxy instance a unique servicePort per host","Use unprivileged ports (>1024) or grant CAP_NET_BIND_SERVICE","In Kubernetes, avoid hostPort collisions across pods on the same node"],"tags":["pulsar-proxy","network","bind-exception","port-in-use","startup"],"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"}