{"record":{"id":"26335d94530bba63","repo":"spring-projects/spring-framework","slug":"beanfactory-must-be-set-on-to-access-qualified","errorCode":null,"errorMessage":"BeanFactory must be set on {} to access qualified executor '{}'","messagePattern":"BeanFactory must be set on (.+?) to access qualified executor '(.+?)'","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java","lineNumber":214,"sourceCode":"\t * been specified and that the {@linkplain #setExecutor(Executor) default executor}\n\t * should be used.\n\t * @param method the method to inspect for executor qualifier metadata\n\t * @return the qualifier if specified, otherwise empty String or {@code null}\n\t * @see #determineAsyncExecutor(Method)\n\t * @see #findQualifiedExecutor(BeanFactory, String)\n\t */\n\tprotected abstract @Nullable String getExecutorQualifier(Method method);\n\n\t/**\n\t * Retrieve a target executor for the given qualifier.\n\t * @param qualifier the qualifier to resolve\n\t * @return the target executor, or {@code null} if none available\n\t * @since 4.2.6\n\t * @see #getExecutorQualifier(Method)\n\t */\n\tprotected @Nullable Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {\n\t\tif (beanFactory == null) {\n\t\t\tthrow new IllegalStateException(\"BeanFactory must be set on \" + getClass().getSimpleName() +\n\t\t\t\t\t\" to access qualified executor '\" + qualifier + \"'\");\n\t\t}\n\t\treturn BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);\n\t}\n\n\t/**\n\t * Retrieve or build a default executor for this advice instance.\n\t * <p>An executor returned from here will be cached for further use.\n\t * <p>The default implementation searches for a unique {@link TaskExecutor} bean\n\t * in the context, or for an {@link Executor} bean named \"taskExecutor\" otherwise.\n\t * If neither of the two is resolvable, this implementation will return {@code null}.\n\t * @param beanFactory the BeanFactory to use for a default executor lookup\n\t * @return the default executor, or {@code null} if none available\n\t * @since 4.2.6\n\t * @see #findQualifiedExecutor(BeanFactory, String)\n\t * @see #DEFAULT_TASK_EXECUTOR_BEAN_NAME\n\t */\n\tprotected @Nullable Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java#L196-L232","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nAsyncExecutionInterceptor interceptor = new AsyncExecutionInterceptor(null);\n// @Async(\"custom\") method invoked -> BeanFactory is null\n\n// after\nAsyncExecutionInterceptor interceptor = new AsyncExecutionInterceptor(null);\ninterceptor.setBeanFactory(context.getBeanFactory());\n// or register it as a bean so BeanFactoryAware wiring happens","handlingStrategy":"validation","validationCode":"AsyncExecutionInterceptor interceptor = new AsyncExecutionInterceptor(null);\nif (methodHasQualifier && interceptor.getBeanFactory() == null) {\n    interceptor.setBeanFactory(context.getBeanFactory());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["spring-aop","async","executor","bean-factory","configuration"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}