spring-projects/spring-framework · error · IllegalStateException
BeanFactory must be set on {} to access qualified executor '
Error message
BeanFactory must be set on {} to access qualified executor '{}' What it means
Thrown by findQualifiedExecutor (line 213-216) when an async method specifies an executor qualifier (e.g. @Async("customExecutor")) but the beanFactory field on the interceptor/advice is null. Looking up a qualified executor requires a BeanFactory to search; without one the lookup cannot proceed and an IllegalStateException is raised.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java:214
* been specified and that the {@linkplain #setExecutor(Executor) default executor}
* should be used.
* @param method the method to inspect for executor qualifier metadata
* @return the qualifier if specified, otherwise empty String or {@code null}
* @see #determineAsyncExecutor(Method)
* @see #findQualifiedExecutor(BeanFactory, String)
*/
protected abstract @Nullable String getExecutorQualifier(Method method);
/**
* Retrieve a target executor for the given qualifier.
* @param qualifier the qualifier to resolve
* @return the target executor, or {@code null} if none available
* @since 4.2.6
* @see #getExecutorQualifier(Method)
*/
protected @Nullable Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
" to access qualified executor '" + qualifier + "'");
}
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);
}
/**
* Retrieve or build a default executor for this advice instance.
* <p>An executor returned from here will be cached for further use.
* <p>The default implementation searches for a unique {@link TaskExecutor} bean
* in the context, or for an {@link Executor} bean named "taskExecutor" otherwise.
* If neither of the two is resolvable, this implementation will return {@code null}.
* @param beanFactory the BeanFactory to use for a default executor lookup
* @return the default executor, or {@code null} if none available
* @since 4.2.6
* @see #findQualifiedExecutor(BeanFactory, String)
* @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME
*/
protected @Nullable Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {View on GitHub (pinned to 69bf83ad71)
Solutions
- Register the interceptor/advice as a Spring bean so that setBeanFactory is invoked automatically (BeanFactoryAware).
- If constructing manually, call 'interceptor.setBeanFactory(beanFactory)' before use.
- Remove the executor qualifier from @Async and instead set an explicit default executor via setExecutor(...) so no BeanFactory lookup is needed.
- Ensure the qualifier value matches a real Executor bean name in the context.
Example fix
// before
AsyncExecutionInterceptor interceptor = new AsyncExecutionInterceptor(null);
// @Async("custom") method invoked -> BeanFactory is null
// after
AsyncExecutionInterceptor interceptor = new AsyncExecutionInterceptor(null);
interceptor.setBeanFactory(context.getBeanFactory());
// or register it as a bean so BeanFactoryAware wiring happens Defensive patterns
Strategy: validation
Validate before calling
AsyncExecutionInterceptor interceptor = new AsyncExecutionInterceptor(null);
if (methodHasQualifier && interceptor.getBeanFactory() == null) {
interceptor.setBeanFactory(context.getBeanFactory());
} Prevention
- Register async interceptors as Spring beans so BeanFactoryAware wiring fires.
- If constructing manually, always call setBeanFactory(...) before use.
- Define a default Executor bean so qualifier lookups are not strictly required.
When it happens
Trigger: Using @Async("qualifier") on a method, or a custom subclass of AsyncExecutionAspectSupport whose getExecutorQualifier returns a non-empty string, while the advice/interceptor was constructed directly (new AsyncExecutionInterceptor(...)) and never had setBeanFactory(...) called (i.e. it was not registered as a BeanFactoryAware bean inside a Spring container).
Common situations: Manually constructing an async interceptor outside the container in tests or a non-Spring-managed setup. Registering the interceptor as a plain bean but losing the BeanFactoryAware callback. Using the @Async annotation's qualifier attribute in a context where the AsyncAnnotationBeanPostProcessor did not wire the BeanFactory onto the advice.
Related errors
- No executor specified and no default executor set on AsyncEx
- AdvisorAutoProxyCreator requires a ConfigurableListableBeanF
- Invalid return type for async method (only Future and void s
- Not running in a ConfigurableBeanFactory: {beanFactory}
- 'argumentNames' property of AbstractAspectJAdvice contains a
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/26335d94530bba63.
Report an issue: GitHub.