apache/pulsar · error · IllegalArgumentException
Could not instantiate <configKeyName> '<factoryClassName>'
Error message
Could not instantiate <configKeyName> '<factoryClassName>'
What it means
instantiateNamedFactory loads a PulsarTlsFactory implementation class by name via Class.forName (preferring the thread context classloader) and instantiates it with a no-arg constructor. If the class cannot be loaded, is not a PulsarTlsFactory, lacks a no-arg constructor, or its constructor fails, an IllegalArgumentException is thrown naming the config key and class.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/tls/ClientTlsFactorySupport.java:341
* Reflectively instantiate a named {@link PulsarTlsFactory} via its public no-arg constructor, failing
* loudly (an {@link IllegalArgumentException} naming the config key) when it cannot be instantiated.
*
* @param factoryClassName the factory class name to instantiate
* @param configKeyName the config key naming it (for the failure message)
* @return the instantiated factory
*/
static PulsarTlsFactory instantiateNamedFactory(String factoryClassName, String configKeyName) {
String name = factoryClassName.trim();
// FIX G: honor the thread context classloader (PulsarAdminImpl sets it to the plugin loader via
// setContextClassLoader) so a factory class visible only through a custom TCCL is found. Plain
// Class.forName(name) uses only this class's defining loader and misses TCCL-only classes. Fall back
// to the defining loader when no TCCL is set.
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
try {
Class<?> clazz = tccl != null ? Class.forName(name, true, tccl) : Class.forName(name);
return (PulsarTlsFactory) clazz.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException(
"Could not instantiate " + configKeyName + " '" + factoryClassName + "'", e);
}
}
/**
* Parse a {@code tlsFactoryConfig} string into the factory init params map (mirrors the server-side
* {@code TlsFactorySupport.parseFactoryConfig}). A blank value yields an empty map; a value starting with
* <code>{</code> is parsed as a JSON object; otherwise it is parsed as a comma-separated
* {@code key=value} list.
*
* @param tlsFactoryConfig the configured factory params (may be null/blank)
* @return an immutable params map (possibly empty)
*/
static Map<String, String> parseFactoryConfig(String tlsFactoryConfig) {
if (StringUtils.isBlank(tlsFactoryConfig)) {
return Map.of();
}
String trimmed = tlsFactoryConfig.trim();View on GitHub (pinned to 820761864e)
Solutions
- Verify the fully-qualified class name in the config is correct and spelled exactly.
- Ensure the factory class is on the client classpath and visible to the thread context classloader.
- Give the factory a public no-arg constructor (parameterless) implementing PulsarTlsFactory.
- Check the factory constructor for throwing code (bad config files, etc.) and fix its initialization.
Example fix
// before
class MyTlsFactory implements PulsarTlsFactory {
public MyTlsFactory(String configPath) { ... }
}
// after
class MyTlsFactory implements PulsarTlsFactory {
public MyTlsFactory() { ... }
public void configure(Map<String,String> params) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
try {
Class<?> c = Class.forName(factoryClassName);
if (!PulsarTlsFactory.class.isAssignableFrom(c)) throw new IllegalArgumentException("not a PulsarTlsFactory");
c.getDeclaredConstructor(); // must exist and be public
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalArgumentException("Bad tls factory class: " + factoryClassName, e);
} Try / catch
try {
buildClientWithTlsFactory(name);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Could not instantiate")) {
log.error("Check class name, classpath, and no-arg constructor", e);
}
} Prevention
- Copy fully-qualified class names from the source, never retype
- Ensure the factory class ships in your client jar/shaded artifact
- Always implement a public no-arg constructor
- Keep constructor side effects minimal; do config in init hooks
When it happens
Trigger: Setting a client TLS factory config key (e.g. tlsFactoryClassName-style configKeyName) to a class name that does not exist, is abstract, has no public no-arg constructor, throws in its constructor, or is not visible to the TCCL.
Common situations: Typo in the fully-qualified class name; class not on the client classpath; custom factory with only a parameterized constructor; shaded/uber-jar excluding the factory class; factory constructor throwing due to bad init.
Related errors
- Failed to instantiate ${className}
- Failed to parse tlsFactoryConfig as a JSON object
- Client TLS configuration is invalid for purpose <purpose>: <
- Could not instantiate ${cls.getName()} either with or withou
- failed to initialize %s field while setting value %s
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/dca22e703100f614.
Report an issue: GitHub.