apache/pulsar · error · IllegalArgumentException
The PIP-337 '${key}' client configuration key is removed in
Error message
The PIP-337 '${key}' client configuration key is removed in Pulsar 5.0 (PIP-478). Migrate the custom SSL factory to a PulsarTlsFactory selected by tlsFactoryClassName / tlsFactoryConfig and remove '${key}' from the configuration. What it means
PIP-478 (Pulsar 5.0) removed the PIP-337 per-connection SSL factory keys (e.g. sslFactoryPlugin / sslFactoryPluginParams style client config keys). During client configuration normalization, ConfigurationDataUtils rejects any of these removed keys unless the value is a *Plugin key still set to the old default factory FQCN (treated as unset). The exception aborts configuration loading with a message telling you to migrate to a PulsarTlsFactory.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/conf/ConfigurationDataUtils.java:75
*
* @param config the client configuration map
* @throws IllegalArgumentException if a removed PIP-337 key is present with a non-default value
*/
public static void rejectRemovedPip337TlsFactoryKeys(Map<String, Object> config) {
if (config == null) {
return;
}
for (String key : REMOVED_PIP337_TLS_FACTORY_KEYS) {
Object value = config.get(key);
if (value == null || StringUtils.isBlank(value.toString())) {
continue;
}
// A *Plugin key still set to the old default factory FQCN means no custom factory — tolerate it as
// if unset. The *PluginParams keys carry no default value, so any non-blank value is rejected.
if (key.endsWith("Plugin") && DEFAULT_PIP337_SSL_FACTORY_CLASS.equals(value.toString().trim())) {
continue;
}
throw new IllegalArgumentException("The PIP-337 '" + key + "' client configuration key is "
+ "removed in Pulsar 5.0 (PIP-478). Migrate the custom SSL factory to a PulsarTlsFactory "
+ "selected by tlsFactoryClassName / tlsFactoryConfig and remove '" + key + "' from the "
+ "configuration.");
}
}
public static ObjectMapper create() {
ObjectMapper mapper = ObjectMapperFactory.create();
// forward compatibility for the properties may go away in the future
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
mapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, false);
mapper.setDefaultPropertyInclusion(Include.NON_NULL);
return mapper;
}
private static final ObjectMapper MAPPER = create();
private ConfigurationDataUtils() {}View on GitHub (pinned to 820761864e)
Solutions
- Remove the removed PIP-337 '${key}' entry from the client configuration map/file.
- Configure the custom SSL factory via tlsFactoryClassName plus tlsFactoryConfig using a PulsarTlsFactory implementation instead of the old plugin mechanism.
- If the *Plugin key only holds the old default factory FQCN, delete it — it was tolerated as unset but should be cleaned up.
- Strip the removed keys defensively when loading legacy properties files (filter by key name before calling loadData).
Example fix
// before
Map<String, Object> conf = new HashMap<>();
conf.put("sslFactoryPlugin", "com.example.MySslFactory");
conf.put("sslFactoryPluginParams", "k=v");
ClientConfigurationData data = ConfigurationDataUtils.newConfigurationData(conf, ClientConfigurationData.class);
// after
Map<String, Object> conf = new HashMap<>();
conf.put("tlsFactoryClassName", "com.example.MyPulsarTlsFactory");
conf.put("tlsFactoryConfig", Map.of("k", "v"));
ClientConfigurationData data = ConfigurationDataUtils.newConfigurationData(conf, ClientConfigurationData.class); Defensive patterns
Strategy: validation
Validate before calling
Set<String> removed = Set.of("sslFactoryPlugin", "sslFactoryPluginParams"); // extend with all PIP-337 keys
removed.forEach(k -> {
if (configMap.containsKey(k)) throw new IllegalStateException("Removed PIP-337 key present: " + k);
}); Type guard
boolean hasRemovedPip337Keys(Map<String,Object> cfg) { return cfg.keySet().stream().anyMatch(k -> k.startsWith("sslFactory")); } Prevention
- Audit client properties files and Helm charts for sslFactory* keys before upgrading to Pulsar 5.0.
- Use tlsFactoryClassName/tlsFactoryConfig exclusively for custom SSL factories.
- Add a startup-time config lint that fails fast on removed keys with a pointer to PIP-478.
When it happens
Trigger: Passing a removed PIP-337 key in the client configuration map via ConfigurationDataUtils.loadData / ConfigurationDataUtils.newConfigurationData, e.g. building a ClientBuilder config from a properties file that still contains the old SSL factory plugin keys, or upgrading an existing client.properties / config map from Pulsar 3.x/4.x to 5.0.
Common situations: Upgrading a Pulsar client from 3.x to 5.0 while reusing old TLS config files; infrastructure-as-code templates or Helm charts that still inject the removed keys; sharing a single config map across brokers (which still accept them) and clients (which no longer do).
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- The replication cluster does not provide TLS encrypted servi
- No ${scheme} URL configured for broker ${brokerId}
- Issuer URL does not use https, but must:
- Failed to get TLS certificates from client
- Client unable to authenticate with TLS certificate
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/4ae5599e3bec3780.
Report an issue: GitHub.