apache/pulsar · error · NotSerializableException

A v5 authentication plugin (${v5Authentication.getClass().ge

Error message

A v5 authentication plugin (${v5Authentication.getClass().getName}) cannot be serialized with the client configuration. Configure authentication with authPluginClassName + authParams instead of a pre-built plugin instance when the configuration has to cross a boundary.

What it means

ClientConfigurationData is Java-serializable, but a pre-built v5 Authentication plugin instance held in the v5Authentication field cannot safely cross a serialization boundary (it holds live state, threads, secrets). During writeObject, if a plugin instance is set and no authPluginClassName is configured, serialization aborts with NotSerializableException, telling you to express auth as class name + params instead.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ClientConfigurationData.java:594

            return operationTimeoutMs;
        }
    }

    /**
     * Refuse to serialize a configuration whose authentication would not survive the round trip.
     *
     * <p>A v5 authentication plugin is not {@link Serializable} and this slot is {@code transient}, so
     * serializing would drop it silently and the deserialized configuration would authenticate as nobody —
     * an authentication downgrade discovered as a broker rejection, far from its cause. The string form
     * ({@code authPluginClassName} + {@code authParams}) does survive, and is what a remote or forked
     * context should be configured with, so a configuration carrying one is allowed through.
     *
     * @param out the object output stream
     * @throws IOException if the configuration cannot be written
     */
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        if (v5Authentication != null && StringUtils.isBlank(authPluginClassName)) {
            throw new NotSerializableException("A v5 authentication plugin ("
                    + v5Authentication.getClass().getName() + ") cannot be serialized with the client "
                    + "configuration. Configure authentication with authPluginClassName + authParams instead "
                    + "of a pre-built plugin instance when the configuration has to cross a boundary.");
        }
        out.defaultWriteObject();
    }

    public ClientConfigurationData clone() {
        try {
            return (ClientConfigurationData) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Failed to clone ClientConfigurationData");
        }
    }

    public InetSocketAddress getSocks5ProxyAddress() {
        if (Objects.nonNull(socks5ProxyAddress)) {
            return socks5ProxyAddress;

View on GitHub (pinned to 820761864e)

Solutions

  1. Set authentication via authPluginClassName + authParams (the string form) before serializing, instead of a pre-built plugin instance.
  2. If you built the plugin programmatically, extract its class name and parameters and configure those on the copy you serialize.
  3. If you must keep the instance, exclude it from serialization (null it out on a copy) and re-instantiate it after deserialization.

Example fix

// before
conf.setAuthentication(myPluginInstance); // then serialize conf
// after
conf.setAuthPluginClassName("org.example.MyAuthPlugin");
conf.setAuthParams("param1=value1");
Defensive patterns

Strategy: validation

Validate before calling

if (conf.getAuthentication() != null /* v5 instance */
        && (conf.getAuthPluginClassName() == null || conf.getAuthPluginClassName().isBlank())) {
    throw new IllegalStateException("set authPluginClassName + authParams before serializing config");
}

Try / catch

try (java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(out)) {
    oos.writeObject(conf);
} catch (java.io.NotSerializableException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("A v5 authentication plugin")) {
        // rebuild conf with authPluginClassName + authParams and retry
    } else throw e;
}

Prevention

When it happens

Trigger: Serializing (java.io.ObjectOutputStream) a ClientConfigurationData whose v5Authentication field holds a plugin instance while authPluginClassName is blank — e.g. shipping the config object over the wire, caching it, or deep-copying via serialization.

Common situations: Frameworks or proxies that serialize client configs between processes; tests that serialize/deserialize configuration; storing configs in a serialized session state after programmatically setting a v5 plugin instance.

Understand the failure class

Related errors


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