apache/pulsar · error · RuntimeException
User class must be concrete
Error message
User class must be concrete
What it means
createInstance instantiates the class reflectively via a no-arg constructor. InstantiationException is thrown by newInstance() when the class is abstract or an interface, so it is wrapped in this RuntimeException. It means the configured user class cannot be instantiated because it is not concrete.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/Reflections.java:90
throw new RuntimeException("User class must be in class path", cnfe);
}
if (!xface.isAssignableFrom(theCls)) {
throw new RuntimeException(userClassName + " does not implement " + xface.getName());
}
@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
*/View on GitHub (pinned to 820761864e)
Solutions
- Configure the fully qualified name of a concrete (non-abstract) class
- Make the class concrete by implementing all abstract methods, or add a concrete subclass and use that
- Check the plugin jar actually contains the concrete implementation, not only the abstract base
Example fix
// before
public abstract class MyFilter implements Filter { }
// after
public class MyConcreteFilter extends MyFilter { } // use MyConcreteFilter in config Defensive patterns
Strategy: validation
Validate before calling
// reject abstract classes/interfaces before instantiation
Class<?> cls = Class.forName(className, true, classLoader);
if (Modifier.isAbstract(cls.getModifiers()) || cls.isInterface()) {
throw new IllegalArgumentException("Configured class must be concrete: " + className);
} Type guard
boolean isConcrete(Class<?> cls) { return !cls.isInterface() && !Modifier.isAbstract(cls.getModifiers()); } Try / catch
try {
T obj = Reflections.createInstance(className, XFace.class, classLoader);
} catch (RuntimeException e) {
if (e.getMessage().equals("User class must be concrete")) {
throw new IllegalArgumentException("Configure a concrete subclass of " + className, e);
}
throw e;
} Prevention
- Reference concrete implementation classes in config, never base/adapter classes
- Check for the implicit-default-constructor trap when adding parameterized constructors
- Ship at least one concrete class in every plugin jar and document its FQN
When it happens
Trigger: Configuring an abstract class or interface name as the user class, so Constructor.newInstance() raises InstantiationException.
Common situations: Pointing config at a base/abstract adapter class instead of a concrete subclass; refactoring left only abstract implementations in a plugin jar.
Related errors
- Failed to instantiate ${className}
- Failed to create instance for key reader class
- Exception caused while converting configuration: ${message}
- Failed to compute configuration overrides
- Could not instantiate <configKeyName> '<factoryClassName>'
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/d7ec9c849e817f65.
Report an issue: GitHub.