apache/pulsar · error · RuntimeException
User class must have a public constructor
Error message
User class must have a public constructor
What it means
After locating the no-arg constructor, createInstance calls setAccessible(true) and newInstance(). IllegalAccessException (e.g. the class or constructor is not public, or the class is in a non-opened package) is wrapped in this RuntimeException whose message says the user class must have a public constructor.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/Reflections.java:94
}
@SuppressWarnings("unchecked") // safe: theCls is verified to be assignable to xface
Class<T> tCls = (Class<T>) theCls.asSubclass(xface);
T result;
try {
@SuppressWarnings("unchecked") // safe: constructor cache is keyed by theCls which extends T
Constructor<T> meth = (Constructor<T>) constructorCache.get(theCls);
if (null == meth) {
meth = tCls.getDeclaredConstructor();
meth.setAccessible(true);
constructorCache.put(theCls, meth);
}
result = meth.newInstance();
} catch (InstantiationException ie) {
throw new RuntimeException("User class must be concrete", ie);
} catch (NoSuchMethodException e) {
throw new RuntimeException("User class must have a no-arg constructor", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("User class must have a public constructor", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("User class constructor throws exception", e);
}
return result;
}
/**
* Create an instance of <code>userClassName</code> using provided <code>classLoader</code>.
*
* @param userClassName user class name
* @param classLoader class loader to load the class.
* @return the instance
*/
public static Object createInstance(String userClassName,
ClassLoader classLoader) {
Class<?> theCls;
try {View on GitHub (pinned to 820761864e)
Solutions
- Make both the class and its no-arg constructor `public`
- If using JPMS, add `opens <package>;` to module-info for the calling module
- Keep constructor visibility public after refactors that add constructors
Example fix
// before
class MyFilter implements Filter { MyFilter() { } }
// after
public class MyFilter implements Filter { public MyFilter() { } } Defensive patterns
Strategy: validation
Validate before calling
// verify public accessibility before instantiation
Class<?> cls = Class.forName(className, true, classLoader);
java.lang.reflect.Constructor<?> c = cls.getDeclaredConstructor();
if (!Modifier.isPublic(cls.getModifiers()) || !Modifier.isPublic(c.getModifiers())) {
throw new IllegalArgumentException("Class and no-arg constructor must be public: " + className);
} Type guard
boolean isPubliclyInstantiable(Class<?> cls) {
try { return Modifier.isPublic(cls.getModifiers()) && Modifier.isPublic(cls.getDeclaredConstructor().getModifiers()); }
catch (NoSuchMethodException e) { return false; }
} Try / catch
try {
T obj = Reflections.createInstance(className, XFace.class, classLoader);
} catch (RuntimeException e) {
if (e.getMessage().equals("User class must have a public constructor")) {
throw new IllegalArgumentException("Make " + className + " and its constructor public", e);
}
throw e;
} Prevention
- Declare plugin classes and constructors `public`
- For JPMS, add `opens <package>` in module-info for packages holding such classes
- Review visibility during refactors that touch constructor modifiers
When it happens
Trigger: Configuring a package-private or private class (or non-public constructor) for reflective instantiation, so newInstance() throws IllegalAccessException even though a no-arg constructor exists.
Common situations: Declaring the plugin class package-private; JPMS module that does not `opens`/`exports` its package to the caller; narrowing constructor visibility during refactoring.
Related errors
- User class must have a no-arg constructor
- Failed to load an authorization provider.
- Failed to instantiate ${className}
- Exception caused while converting configuration: ${message}
- Failed to compute configuration overrides
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/5a37c48a113e4219.
Report an issue: GitHub.