apache/pulsar · error · IllegalArgumentException
host must not be null
Error message
host must not be null
What it means
IllegalArgumentException thrown by MultipleListenerValidator.formatHostPort(URI) when the URI's host component is null. A URI like pulsar:///path or one with an unparseable authority yields getHost()==null; since the helper must render host:port for advertised-listener validation, it fails fast instead of producing a malformed host string.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/validator/MultipleListenerValidator.java:52
/**
* Validates multiple listener address configurations.
*/
public final class MultipleListenerValidator {
/** Allowed listener-name characters: ASCII letters, digits, underscore, hyphen. */
private static final Pattern LISTENER_NAME_PATTERN = Pattern.compile("[A-Za-z0-9_-]+");
/**
* Format the host:port part of a URI for use as a uniqueness key and in error messages, wrapping
* IPv6 literals in brackets so that the colon separator is unambiguous. {@link URI#getHost()} may
* or may not include the brackets depending on the JDK, so they are stripped before the
* {@link NetUtil#isValidIpV6Address} check.
*/
static String formatHostPort(URI uri) {
String host = uri.getHost();
if (host == null) {
throw new IllegalArgumentException("host must not be null");
}
String unbracketed = host.startsWith("[") && host.endsWith("]")
? host.substring(1, host.length() - 1) : host;
if (NetUtil.isValidIpV6Address(unbracketed)) {
return "[" + unbracketed + "]:" + uri.getPort();
}
return host + ":" + uri.getPort();
}
/**
* Validate a listener name. Listener names must be non-blank and contain only ASCII letters,
* digits, underscore, and hyphen so they are safe to embed in URLs without encoding.
*
* @throws IllegalArgumentException if the name is null, blank, or contains disallowed characters.
*/
public static void validateListenerName(String name) {
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("listener name must not be blank");View on GitHub (pinned to 820761864e)
Solutions
- Always include an explicit host in listener URLs; bracket IPv6 addresses: pulsar://[fe80::1]:6650
- Check the URL with new URI(s) and assert getHost() != null before passing it in
- Remove illegal characters from the hostname
- If constructing URIs programmatically, use URI(scheme, host, port, ...) so the host is encoded correctly
Example fix
// before String url = "pulsar://fe80::1:6650"; // getHost() == null // after String url = "pulsar://[fe80::1]:6650"; // getHost() == "fe80::1"
Defensive patterns
Strategy: validation
Validate before calling
static boolean hasHost(String listenerUrl) {
try {
URI uri = URI.create(listenerUrl);
return uri.getHost() != null && !uri.getHost().isEmpty();
} catch (IllegalArgumentException e) {
return false;
}
} Type guard
static boolean isParseableListenerUri(URI uri) {
return uri != null && uri.getHost() != null;
} Prevention
- Bracket IPv6 literals: pulsar://[::1]:6650
- Never omit the host part of listener URLs
- Test URIs with new URI(...).getHost() before configuring
- Reject configs whose listener URL fails URI parsing in CI
When it happens
Trigger: Passing a URI built from a listener URL with no host (e.g. pulsar://:6650) or an authority the JDK URI parser cannot decompose (unbracketed IPv6 like pulsar://fe80::1:6650, illegal characters in the host) — getHost() returns null in both cases.
Common situations: Writing IPv6 advertised listeners without square brackets; omitting the host and keeping only the port; typos or special characters in hostnames that make URI parsing fail silently to null host.
Related errors
- bindAddresses: malformed: ${address}
- bindAddresses: conflicting listener names for ${address}: `$
- listener name must not be blank
- listener name `${name}` must contain only ASCII letters, dig
- the `advertisedListeners` configuration does not contain an
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9b29c75776665711.
Report an issue: GitHub.