apache/pulsar · error · IllegalArgumentException

bindAddresses: malformed: ${address}

Error message

bindAddresses: malformed: ${address}

What it means

IllegalArgumentException thrown by BindAddressValidator.validateBindAddresses when an entry in the broker's bindAddresses configuration does not match the required pattern listenerName:scheme://host:port (e.g. mylistener:pulsar://127.0.0.1:6650). The validator splits bindAddresses on commas and requires each non-empty segment to fully match BIND_ADDRESSES_PATTERN; anything else fails fast at broker startup.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/validator/BindAddressValidator.java:75

     * @param schemes a filter on the schemes of the bind addresses, or null to not apply a filter.
     * @return a list of bind addresses.
     */
    public static List<BindAddress> validateBindAddresses(ServiceConfiguration config, Collection<String> schemes) {
        String internalListenerName = StringUtils.defaultIfBlank(config.getInternalListenerName(),
                ServiceConfiguration.DEFAULT_INTERNAL_LISTENER_NAME);

        // migrate the legacy port-based configuration to bind addresses tagged with the internal listener name
        List<BindAddress> addresses = migrateBindAddresses(config, internalListenerName);

        // parse the list of additional bind addresses; trim whitespace around the comma-separated
        // entries so configurations split across multiple lines or padded for readability are accepted
        Arrays.stream(StringUtils.split(StringUtils.defaultString(config.getBindAddresses()), ","))
                .map(StringUtils::trim)
                .filter(StringUtils::isNotEmpty)
                .map(s -> {
                    Matcher m = BIND_ADDRESSES_PATTERN.matcher(s);
                    if (!m.matches()) {
                        throw new IllegalArgumentException("bindAddresses: malformed: " + s);
                    }
                    return m;
                })
                .map(m -> {
                    String name = StringUtils.trim(m.group("name"));
                    MultipleListenerValidator.validateListenerName(name);
                    return new BindAddress(name, URI.create(StringUtils.trim(m.group("url"))));
                })
                .forEach(addresses::add);

        // apply the filter
        if (schemes != null) {
            addresses.removeIf(a -> !schemes.contains(a.getAddress().getScheme()));
        }

        // Deduplicate by full URI (scheme + ip + port). Tolerate exact duplicates (same URI and
        // same listener name) so that a user's bindAddresses entry that matches a migrated binding
        // is accepted; reject same URI assigned to different listener names.

View on GitHub (pinned to 820761864e)

Solutions

  1. Rewrite each entry as <listenerName>:<scheme>://<host>:<port>, e.g. internal:pulsar://0.0.0.0:6650
  2. Verify the listener name contains only ASCII letters, digits, underscore, hyphen
  3. Check the pattern with a quick regex test before restarting
  4. Remove empty/stray segments or extra commas from the comma-separated list

Example fix

// before (broker.conf)
bindAddresses=pulsar://0.0.0.0:6650,pulsar+ssl://0.0.0.0:6651
// after
bindAddresses=internal:pulsar://0.0.0.0:6650,internalsecure:pulsar+ssl://0.0.0.0:6651
Defensive patterns

Strategy: validation

Validate before calling

for (String s : bindAddresses.split(",")) {
    s = s.trim();
    if (!s.isEmpty() && !s.matches("[A-Za-z0-9_-]+:[a-zA-Z+.-]+://[^:/]+:[0-9]+")) {
        throw new IllegalArgumentException("Malformed bindAddresses entry: " + s);
    }
}

Prevention

When it happens

Trigger: Configuring bindAddresses with an entry lacking the listener-name prefix (e.g. just pulsar://0.0.0.0:6650), missing scheme, missing port, containing unescaped commas/spaces that break segmentation, or using a name with invalid characters rejected by MultipleListenerValidator.validateListenerName.

Common situations: Migrating from the legacy bindAddress field to multi-listener bindAddresses and forgetting the 'name:' prefix; typos like double colons or omitting the scheme; copying advertisedListeners-style URLs into bindAddresses; whitespace after commas in multi-value configs.

Understand the failure class

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/b149ef3c9a355eb3. Report an issue: GitHub.