{"record":{"id":"1601809196625105","repo":"apache/pulsar","slug":"the-advertisedlisteners-configuration-does-not-c","errorCode":null,"errorMessage":"the `advertisedListeners` configuration does not contain an entry for the internal listener `${internalListenerName}`, and the legacy port properties are not configured so an internal listener cannot be synthesized","messagePattern":"the `advertisedListeners` configuration does not contain an entry for the internal listener `(.+?)`, and the legacy port properties are not configured so an internal listener cannot be synthesized","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-broker-common/src/main/java/org/apache/pulsar/broker/validator/MultipleListenerValidator.java","lineNumber":130,"sourceCode":"            String fallback = result.isEmpty()\n                    ? ServiceConfiguration.DEFAULT_INTERNAL_LISTENER_NAME\n                    : result.keySet().iterator().next();\n            config.setInternalListenerName(fallback);\n        }\n        String internalListenerName = config.getInternalListenerName();\n\n        // Merge the legacy-port-derived internal listener URLs into any explicit configuration.\n        // Explicit URLs in `advertisedListeners` take precedence; the legacy-port URLs fill in the\n        // unspecified slots so that broker-to-broker communication keeps working without forcing the\n        // user to redeclare every URL when they only want to override one.\n        AdvertisedListener fromLegacyPorts = buildInternalListenerFromLegacyPorts(config);\n        if (fromLegacyPorts != null) {\n            AdvertisedListener explicit = result.get(internalListenerName);\n            result.put(internalListenerName, mergeListeners(explicit, fromLegacyPorts));\n        }\n\n        if (!result.isEmpty() && !result.containsKey(internalListenerName)) {\n            throw new IllegalArgumentException(\"the `advertisedListeners` configuration does not contain \"\n                    + \"an entry for the internal listener `\" + internalListenerName + \"`, and the legacy \"\n                    + \"port properties are not configured so an internal listener cannot be synthesized\");\n        }\n\n        return result;\n    }\n\n    /**\n     * Merges two {@link AdvertisedListener} entries. URLs from {@code override} take precedence; URLs\n     * from {@code fallback} only fill in the slots that {@code override} leaves null. Either argument\n     * may be null.\n     */\n    private static AdvertisedListener mergeListeners(AdvertisedListener override, AdvertisedListener fallback) {\n        if (override == null) {\n            return fallback;\n        }\n        if (fallback == null) {\n            return override;","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/validator/MultipleListenerValidator.java#L112-L148","documentation":"IllegalArgumentException thrown by MultipleListenerValidator.validateAndUpdateAdvertisedListeners when advertisedListeners is non-empty but contains no entry for the configured internal listener, and the legacy port properties (port/portTls/portHttp/portHttps) are not set, so an internal listener cannot be synthesized by merging legacy ports. Every broker must know its internal listener for broker-to-broker and client redirect URLs.","triggerScenarios":"Setting advertisedListeners to names other than the internalListenerName config value (e.g. listeners named 'external' only) while removing the legacy port/portTls properties; renaming a listener without updating internalListenerName; upgrading from a legacy single-listener config and dropping port properties while giving advertisedListeners different names.","commonSituations":"Helm/k8s deployments where advertisedListeners was templated for external access but internalListenerName kept its default; operators migrating off legacy ports to multi-listener config; typo where the internal listener key differs by case or suffix.","solutions":["Add an entry for the internal listener to advertisedListeners, e.g. internal:pulsar://<advertised-host>:6650","Or set internalListenerName to one of the names present in advertisedListeners","Or keep the legacy port (and portTls) properties so an internal listener can be synthesized and merged","Ensure internalListenerName matches an advertisedListeners key exactly"],"exampleFix":"// before\nadvertisedListeners=external:pulsar+ssl://broker.example.com:6651\ninternalListenerName=internal\n// after\nadvertisedListeners=external:pulsar+ssl://broker.example.com:6651,internal:pulsar://10.0.0.5:6650\ninternalListenerName=internal","handlingStrategy":"validation","validationCode":"Map<String,String> listeners = parseAdvertisedListeners(conf.getAdvertisedListeners());\nString internal = conf.getInternalListenerName();\nboolean legacyPortsSet = conf.getPort() > 0 || conf.getPortTls() > 0;\nif (!listeners.isEmpty() && !listeners.containsKey(internal) && !legacyPortsSet) {\n    throw new IllegalArgumentException(\"advertisedListeners must contain internal listener '\" + internal + \"' or legacy ports must be set\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include the internal listener in advertisedListeners","Keep internalListenerName in sync when renaming listeners","Retain legacy port properties during migrations as a safety net","Assert the invariant in deployment charts before apply"],"tags":["configuration","advertised-listeners","multi-listener","broker"],"backgroundTag":"missing-internal-listener","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}