apache/pulsar · error · IllegalArgumentException

${name} is NULL, empty or contains a '&'

Error message

${name} is NULL, empty or contains a '&'

What it means

IllegalArgumentException from SaslRoleToken.checkForIllegalArgument, thrown by the SaslRoleToken constructors when userRole or session is null, empty, or contains the '&' attribute separator character. '&' is the delimiter used in the serialized token string (u=..&i=..&e=..), so a value containing it would corrupt the token format and is rejected up front.

Source

Thrown at pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/SaslRoleToken.java:94

    public SaslRoleToken(String userRole, String session, long expires) {
        checkForIllegalArgument(userRole, "userRole");
        checkForIllegalArgument(session, "session");
        this.userRole = userRole;
        this.session = session;
        this.expires = expires;
        generateToken();
    }

    /**
     * Check if the provided value is invalid. Throw an error if it is invalid, NOP otherwise.
     *
     * @param value the value to check.
     * @param name the parameter name to use in an error message if the value is invalid.
     */
    private static void checkForIllegalArgument(String value, String name) {
        if (value == null || value.length() == 0 || value.contains(ATTR_SEPARATOR)) {
            throw new IllegalArgumentException(name + ILLEGAL_ARG_MSG);
        }
    }

    /**
     * Sets the expiration of the token.
     *
     * @param expires expiration time of the token in milliseconds since the epoch.
     */
    public void setExpires(long expires) {
        if (this != SaslRoleToken.ANONYMOUS) {
            this.expires = expires;
            generateToken();
        }
    }

    /**
     * Generates the token.
     */

View on GitHub (pinned to 820761864e)

Solutions

  1. Validate inputs before constructing: reject or sanitize values that are null, empty, or contain '&' (URL-encode or strip the character)
  2. Use a generated session identifier (UUID or similar) rather than assembling one from user-controlled strings
  3. If '&' must be preserved in userRole, escape/encode it (e.g. percent-encoding) before constructing the token and decode after parse
  4. Catch IllegalArgumentException at the API boundary and return a 4xx-style authentication error identifying the offending parameter

Example fix

// before
SaslRoleToken token = new SaslRoleToken(userName, sessionId); // throws if userName is null or contains '&'
// after
if (userName == null || userName.isEmpty() || userName.contains("&")) {
    throw new IllegalArgumentException("userRole is NULL, empty or contains a '&'");
}
String safeUserName = URLEncoder.encode(userName, StandardCharsets.UTF_8);
SaslRoleToken token = new SaslRoleToken(safeUserName, sessionId);
Defensive patterns

Strategy: validation

Validate before calling

// run before new SaslRoleToken(userRole, session[, expires])
static void validateTokenInput(String userRole, String session) {
    if (userRole == null || userRole.isEmpty() || userRole.contains("&")) {
        throw new IllegalArgumentException("userRole is NULL, empty or contains a '&'");
    }
    if (session == null || session.isEmpty() || session.contains("&")) {
        throw new IllegalArgumentException("session is NULL, empty or contains a '&'");
    }
}

Try / catch

try {
    SaslRoleToken token = new SaslRoleToken(userRole, session);
} catch (IllegalArgumentException e) {
    // parameter name is prefixed in the message ("session is NULL, empty or contains a '&'")
    throw new AuthenticationException("Invalid token parameter: " + e.getMessage());
}

Prevention

When it happens

Trigger: new SaslRoleToken(userRole, session) with null/empty session or a session containing '&' (the 2-arg constructor checks session only); new SaslRoleToken(userRole, session, expires) with null/empty userRole or session or either containing '&' (e.g. a Kerberos principal like user/host@REALM isn't affected, but a name containing '&' is); SaslRoleToken.parse passing a value extracted from a malformed token string into the constructor.

Common situations: Caller builds a token from unvalidated user input where the username contains '&' (e.g. a display name or email-derived role); session id accidentally built by joining values with '&'; a null/empty session because the upstream authentication step produced no session identifier; unit/custom code constructing tokens by hand.

Related errors


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