spring-projects/spring-framework · error · IllegalStateException
Failed to load Class [
Error message
Failed to load Class [
What it means
Thrown as an IllegalStateException during AOT code generation when a bean's init/destroy method name is fully qualified (contains a '.' specifying a declaring class other than the bean class) and ClassUtils.forName cannot load that class through the bean class's ClassLoader. The generator (BeanDefinitionPropertiesCodeGenerator.addInitDestroyHint) parses the prefix off the method name to register a reflection hint on the real declaring class; if that class is absent from the classpath/native-image, generation aborts.
Source
Thrown at spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java:182
.collect(CodeBlock.joining(", "));
code.addStatement(format, BEAN_DEFINITION_VARIABLE, arguments);
}
}
private void addInitDestroyHint(Class<?> beanUserClass, String methodName) {
Class<?> methodDeclaringClass = beanUserClass;
// Parse fully-qualified method name if necessary.
int indexOfDot = methodName.lastIndexOf('.');
if (indexOfDot > 0) {
String className = methodName.substring(0, indexOfDot);
methodName = methodName.substring(indexOfDot + 1);
if (!beanUserClass.getName().equals(className)) {
try {
methodDeclaringClass = ClassUtils.forName(className, beanUserClass.getClassLoader());
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to load Class [" + className +
"] from ClassLoader [" + beanUserClass.getClassLoader() + "]", ex);
}
}
}
Method method = ReflectionUtils.findMethod(methodDeclaringClass, methodName);
if (method != null) {
this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
Method publiclyAccessibleMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(method, beanUserClass);
if (!publiclyAccessibleMethod.equals(method)) {
this.hints.reflection().registerMethod(publiclyAccessibleMethod, ExecutableMode.INVOKE);
}
}
}
private void addConstructorArgumentValues(CodeBlock.Builder code, BeanDefinition beanDefinition) {
ConstructorArgumentValues constructorValues = beanDefinition.getConstructorArgumentValues();
Map<Integer, ValueHolder> indexedValues = constructorValues.getIndexedArgumentValues();View on GitHub (pinned to 69bf83ad71)
Solutions
- Make sure the fully-qualified class used as the init/destroy method prefix is on the AOT build classpath and reachable by the bean's ClassLoader.
- If the method actually lives on the bean class itself, remove the class prefix and specify just the method name.
- Fix the typo or stale FQN in the XML init-method/destroy-method attribute or @Bean(initMethod=...) / destroyMethod.
- If the class is intentionally optional, register a substitute init/destroy method that does not reference it, or guard the bean definition so it isn't processed when the class is absent.
- Run the native build with --debug to see the exact class name and ClassLoader that failed, then add the missing artifact as a dependency.
Example fix
// before: prefix class missing from native image
@Bean(initMethod = "com.acme.legacy.Lifecycle.start")
public MyBean myBean() { ... }
// after: method on the bean class itself, no FQN prefix
@Bean(initMethod = "start")
public MyBean myBean() { ... } Defensive patterns
Strategy: validation
Validate before calling
// Validate a fully-qualified init/destroy method before AOT runs
String m = "com.acme.Helper.init";
int dot = m.lastIndexOf('.');
if (dot <= 0) throw new IllegalArgumentException("Bad method spec: " + m);
Class<?> cls = ClassUtils.forName(m.substring(0, dot), beanClassLoader);
Assert.notNull(ReflectionUtils.findMethod(cls, m.substring(dot + 1)),
() -> "Method not found: " + m); Prevention
- Prefer init/destroy method names without a class prefix unless the declaring class truly differs.
- Add the artifact containing the declaring class to the native build dependencies.
- Run a clean AOT build after refactoring class packages or names.
- Lint XML/annotations for fully-qualified init/destroy method values in CI.
When it happens
Trigger: A bean definition carries an init-method or destroy-method value like 'com.acme.Helper.init' where 'com.acme.Helper' is not resolvable by the bean class's ClassLoader at AOT build time. Triggered when BeanDefinitionPropertiesCodeGenerator is generating the bean-definition properties code and the prefix class load fails.
Common situations: Specifying an init/destroy method on a class that lives in an optional dependency not on the AOT classpath; renaming/moving the helper class without updating XML or @Bean(initMethod=...) values; GraalVM native-image build pruning a class that is only referenced by string in a method name; multi-module build where the module containing the declaring class is not on the compile classpath.
Related errors
- Unsatisfied dependency expressed through injection point
- Failed to instantiate method
- failed to generate code for bean definition
- instance supplier is not supported
- Invocation of init method failed
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/58f49d1d83316c79.
Report an issue: GitHub.