spring-projects/spring-framework · error · IllegalStateException
Cannot invoke instance method without factoryBeanName:
Error message
Cannot invoke instance method without factoryBeanName:
What it means
Thrown as an IllegalStateException when the BeanInstanceSupplier is told to invoke a factory method that is non-static, but the bean definition has no factoryBeanName set. Without a factoryBeanName the supplier has no bean to obtain as the invocation target, so it refuses rather than NPE on method.invoke(null, args).
Solutions
- Set the factoryBeanName on the bean definition: definition.setFactoryBeanName("myFactory"); so the supplier can resolve the target bean.
- If the factory method should not need an instance, mark it static so the supplier can invoke it without a target.
- Regenerate AOT artifacts after changing a @Bean method between static and instance forms so the metadata matches the code.
- Validate the bean definition programmatically (factoryBeanName != null XOR Modifier.isStatic(factoryMethod)) before publishing it.
Example fix
// before: instance factory method without a factoryBeanName
RootBeanDefinition bd = new RootBeanDefinition(MyBean.class);
bd.setFactoryMethodName("create"); // create() is non-static
// after: provide the factory bean name
bd.setFactoryBeanName("myFactory");
bd.setFactoryMethodName("create"); Defensive patterns
Strategy: validation
Validate before calling
// Validate factory-method metadata before publishing a bean definition
RootBeanDefinition bd = (RootBeanDefinition) beanDefinition;
Method fm = /* resolved factory method */;
if (!Modifier.isStatic(fm.getModifiers()) && bd.getFactoryBeanName() == null) {
throw new IllegalStateException("Instance factory method requires factoryBeanName: " + fm);
} Type guard
// True if the bean definition can be invoked without an instance target boolean canInvoke = Modifier.isStatic(method.getModifiers()) || factoryBeanName != null;
Prevention
- Always set factoryBeanName for instance factory methods in programmatic definitions.
- Prefer @Bean methods on @Configuration classes over hand-built RootBeanDefinition.
- Regenerate AOT artifacts after changing a factory method's static/instance form.
- Add a BeanDefinition validation post-processor that checks this invariant.
When it happens
Trigger: The instantiation descriptor select a java.lang.reflect.Method that is an instance method (not static), but RootBeanDefinition.getFactoryBeanName() returns null. Triggered in BeanInstanceSupplier.instantiate when building the bean instance via reflection at runtime.
Common situations: Programmatically building a RootBeanDefinition with setFactoryMethodName(name) on an instance method but forgetting setFactoryBeanName(...); a @Bean method that was inadvertently changed from static to instance without updating factory metadata; custom BeanDefinitionRegistryPostProcessor that misconfigures factory method metadata; stale AOT metadata generated against a static factory that later became an instance method.
Related errors
- Could not process key '
- Error registering bean definition
- failed to generate code for bean definition
- No StringValueResolver specified - pass a resolver object…
- no suitable constructor or factory method found
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/9a5f54891b6ca094.
Report an issue: GitHub.
Appendix: source
Thrown at spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java:361
}
private Object instantiate(RegisteredBean registeredBean, Executable executable, @Nullable Object[] args) {
if (executable instanceof Constructor<?> constructor) {
if (registeredBean.getBeanFactory() instanceof DefaultListableBeanFactory dlbf &&
registeredBean.getMergedBeanDefinition().hasMethodOverrides()) {
return dlbf.getInstantiationStrategy().instantiate(registeredBean.getMergedBeanDefinition(),
registeredBean.getBeanName(), registeredBean.getBeanFactory());
}
return BeanUtils.instantiateClass(constructor, args);
}
if (executable instanceof Method method) {
Object target = null;
String factoryBeanName = registeredBean.getMergedBeanDefinition().getFactoryBeanName();
if (factoryBeanName != null) {
target = registeredBean.getBeanFactory().getBean(factoryBeanName, method.getDeclaringClass());
}
else if (!Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("Cannot invoke instance method without factoryBeanName: " + method);
}
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (Throwable ex) {
throw new BeanInstantiationException(method, ex.getMessage(), ex);
}
}
throw new IllegalStateException("Unsupported executable " + executable.getClass().getName());
}
private static String toCommaSeparatedNames(Class<?>... parameterTypes) {
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
}
View on GitHub (pinned to 69bf83ad71)