As mentioned in the release notes of spring boot 3.5 the bean name "taskExecutor" was removed -> https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes#auto-configured-taskexecutor-names
But the class AsyncExecutionAspectSupport uses this bean name to search for the default task executor -> https://github.com/spring-projects/spring-framework/blob/0319fe92114d6e7c5c39b2cbe36dc6ba19040616/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java#L244
So either the name "taskExecutor" needs to be added again (which is my current workaround) or the default look up in AsyncExecutionAspectSupport must use the name "applicationTaskExecutor".
Comment From: wilkinsona
It only uses taskExecutor when there are multiple beans in the context and it needs to choose one. Without knowing more about your application, we can't tell why you have multiple executors. If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Comment From: spec8472
Yes, that's true, the bug only occurs with multiple executors. To have multiple executors you just have to use @EnableAsync and @EnableScheduling together, which is very common in my opinion. With just that everything still works fine. The bug occurs when you define a AsyncConfigurer without overriding getAsyncExecutor(). Now the default lookup fails because of the name.
I added a minimal project setup. If you run the test you will see the following log message: More than one TaskExecutor bean found within the context, and none is named 'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly as an alias) in order to use it for async processing: [applicationTaskExecutor, taskScheduler]
The method is still executed async but does not use the configured "applicationTaskExecutor" but an unconfigured "SimpleAsyncTaskExecutor".
Comment From: snicoll
I've ran your sample and got the following log:
2025-10-30T15:18:43.009+01:00 INFO 45587 --- [demo] [ main] .s.a.AnnotationAsyncExecutionInterceptor : More than one TaskExecutor bean found within the context, and none is named 'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly as an alias) in order to use it for async processing: [applicationTaskExecutor, taskScheduler]
It's not obvious why the fallback doesn't apply when you implement AsyncConfigurer partially. I'll transfer that to the framework team for their consideration.
Comment From: jhoeller
The problem here is that a custom AsyncConfigurer replaces the Boot-provided one from TaskExecutorConfigurations.AsyncConfigurerConfiguration - which is where the applicationTaskExecutor lookup is implemented in Boot. So once a custom AsyncConfigurer replaces this, the standard Framework-level lookup kicks in which only looks for a taskExecutor bean to select among multiple matches.
I'm not quite sure how to resolve this since applicationTaskExecutor is a Boot-specific bean name. I suppose we could pick a bean named ...TaskExecutor among the matches if there is only one such bean but that would be a new rule in our Framework-level lookup algorithm.
Fundamentally, this regression comes from Boot 3.5 not exposing a taskExecutor bean name anymore, and its applicationTaskExecutor lookup being implemented through an internal AsyncConfigurer now that users cannot transparently replace anymore.
Comment From: snicoll
@spec8472 I am not sure what we're going to do. In the meantime you can change your configurer as follows:
@Override
public Executor getAsyncExecutor() {
return beanFactory.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME,
Executor.class);
}
Comment From: snicoll
We've decided to not backport the fix. I've updated the release notes of 3.5 to include an example of the workaround above.