apache/pulsar · error · IllegalArgumentException

v4 authentication must not be null

Error message

v4 authentication must not be null

What it means

LegacyV4AuthenticationAdapter wraps an old (v4) org.apache.pulsar.client.api.Authentication plugin so it can be used with the v5 authentication framework. wrap() (private, used by both wrap and wrapAlreadyStarted) rejects a null v4 plugin immediately with this IllegalArgumentException, since there is nothing to adapt.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/v5/LegacyV4AuthenticationAdapter.java:143

     * {@code close} the caller will perform.
     *
     * <p>This is the client's own path. The client keeps the configured v4 plugin in its configuration and
     * starts it during construction — the v4 instance remains observable, and several client-side features
     * (notably folding an auth plugin's TLS material into the client's TLS policy) read it directly. The
     * adapter that lets the client <em>drive</em> that plugin through the v5 model must therefore not run
     * the lifecycle a second time: {@code AuthenticationOAuth2.start()} initializes the token flow, so a
     * second {@code start()} is not a harmless no-op.
     *
     * @param v4 the already-configured, already-started v4 authentication plugin
     * @return a v5 {@link Authentication} that delegates to the v4 plugin without re-running its lifecycle
     */
    public static Authentication wrapAlreadyStarted(org.apache.pulsar.client.api.Authentication v4) {
        return wrap(v4, false);
    }

    private static Authentication wrap(org.apache.pulsar.client.api.Authentication v4, boolean ownsLifecycle) {
        if (v4 == null) {
            throw new IllegalArgumentException("v4 authentication must not be null");
        }
        if (v4 instanceof AuthenticationDisabled) {
            return NoAuthentication.INSTANCE;
        }
        String methodName = v4.getAuthMethodName();
        if (TlsAuthentication.DEFAULT_AUTH_METHOD_NAME.equalsIgnoreCase(methodName)) {
            return new LegacyV4TlsAdapter(v4, ownsLifecycle);
        }
        if ("sasl".equalsIgnoreCase(methodName)) {
            return new LegacyV4ChallengeResponseAdapter(v4, ownsLifecycle);
        }
        return new LegacyV4CredentialAdapter(v4, ownsLifecycle);
    }

    /**
     * Unwrap the v4 {@link org.apache.pulsar.client.api.Authentication} that a {@link #wrap}-produced
     * v5 adapter delegates to, if any. This is the inverse of {@link #wrap} — it recovers the wrapped v4
     * plugin for any bridged adapter (used by the v5 client builder to inspect a bridged plugin's TLS

View on GitHub (pinned to 820761864e)

Solutions

  1. Pass a non-null v4 Authentication instance; if auth is intentionally disabled, pass AuthenticationDisabled (it maps to NoAuthentication.INSTANCE).
  2. Null-check the v4 plugin before calling the adapter and fall back to AuthenticationDisabled when no plugin is configured.
  3. Fix the upstream factory/registry so it never returns null for a configured auth plugin.

Example fix

// before
Authentication v5 = LegacyV4AuthenticationAdapter.wrap(conf.getAuthentication()); // may be null
// after
org.apache.pulsar.client.api.Authentication v4 = conf.getAuthentication();
Authentication v5 = v4 == null
        ? NoAuthentication.INSTANCE
        : LegacyV4AuthenticationAdapter.wrap(v4);
Defensive patterns

Strategy: validation

Validate before calling

if (v4 == null) {
    v4 = new AuthenticationDisabled(); // or skip adapter entirely
}

Type guard

static boolean isWrappable(org.apache.pulsar.client.api.Authentication a) {
    return a != null;
}

Try / catch

try {
    v5 = LegacyV4AuthenticationAdapter.wrap(v4);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("must not be null")) {
        v5 = NoAuthentication.INSTANCE;
    } else throw e;
}

Prevention

When it happens

Trigger: Calling LegacyV4AuthenticationAdapter.wrap(v4) or wrapAlreadyStarted(v4) with a null argument, typically because authentication resolution returned null before wrapping.

Common situations: Client configuration code that builds the v4 Authentication instance conditionally and passes the null result into the adapter; refactors where a lookup map or registry returns null for an unknown auth class name.

Understand the failure class

Related errors


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