{"record":{"id":"3768a31f8fa58bb2","repo":"spring-projects/spring-framework","slug":"no-executor-specified-and-no-default-executor-set","errorCode":null,"errorMessage":"No executor specified and no default executor set on AsyncExecutionInterceptor either","messagePattern":"No executor specified and no default executor set on AsyncExecutionInterceptor either","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java","lineNumber":106,"sourceCode":"\t\tsuper(defaultExecutor, exceptionHandler);\n\t}\n\n\n\t/**\n\t * Intercept the given method invocation, submit the actual calling of the method to\n\t * the correct task executor and return immediately to the caller.\n\t * @param invocation the method to intercept and make asynchronous\n\t * @return {@link Future} if the original method returns {@code Future}; {@code null}\n\t * otherwise.\n\t */\n\t@Override\n\tpublic @Nullable Object invoke(final MethodInvocation invocation) throws Throwable {\n\t\tClass<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);\n\t\tfinal Method userMethod = BridgeMethodResolver.getMostSpecificMethod(invocation.getMethod(), targetClass);\n\n\t\tAsyncTaskExecutor executor = determineAsyncExecutor(userMethod);\n\t\tif (executor == null) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"No executor specified and no default executor set on AsyncExecutionInterceptor either\");\n\t\t}\n\n\t\tCallable<Object> task = () -> {\n\t\t\ttry {\n\t\t\t\tObject result = invocation.proceed();\n\t\t\t\tif (result instanceof Future<?> future) {\n\t\t\t\t\treturn future.get();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ExecutionException ex) {\n\t\t\t\tThrowable cause = ex.getCause();\n\t\t\t\thandleError(cause == null ? ex : cause, userMethod, invocation.getArguments());\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\thandleError(ex, userMethod, invocation.getArguments());\n\t\t\t}\n\t\t\treturn null;","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java#L88-L124","documentation":"Thrown in AsyncExecutionInterceptor.invoke (line 105-107) when determineAsyncExecutor returns null, meaning no executor could be resolved for the method - neither a qualifier-matched executor nor a default. AsyncExecutionInterceptor.getDefaultExecutor (line 155-157) normally falls back to a SimpleAsyncTaskExecutor, so reaching this error means a subclass overrode getDefaultExecutor to return null and no explicit executor was supplied.","triggerScenarios":"Subclassing AsyncExecutionInterceptor (or AsyncExecutionAspectSupport) and overriding getDefaultExecutor to return null, while not calling setExecutor(...) with a concrete Executor and not having a resolvable TaskExecutor bean in the context. Invoking the async method then yields a null executor and the IllegalStateException.","commonSituations":"Disabling the SimpleAsyncTaskExecutor fallback to enforce an explicit executor policy but forgetting to register/qualify one. Removing the 'taskExecutor' bean from a context that previously provided the default. Configuring an AsyncConfigurer that returns null from getAsyncExecutor() while no TaskExecutor bean exists.","solutions":["Provide an explicit default executor: call setExecutor(new ThreadPoolTaskExecutor()) or return one from an AsyncConfigurer.getAsyncExecutor().","Define a TaskExecutor bean (or a bean named 'taskExecutor') in the context so getDefaultExecutor can resolve it.","If you overrode getDefaultExecutor, either keep the SimpleAsyncTaskExecutor fallback or guarantee an executor is always set via setExecutor.","For @Async(\"qualifier\"), make sure the named Executor bean actually exists."],"exampleFix":"// before\n@Configuration @EnableAsync\npublic class AsyncConfig implements AsyncConfigurer {\n    public Executor getAsyncExecutor() { return null; } // no fallback bean either\n}\n\n// after\n@Configuration @EnableAsync\npublic class AsyncConfig implements AsyncConfigurer {\n    public Executor getAsyncExecutor() {\n        ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();\n        ex.initialize();\n        return ex;\n    }\n}","handlingStrategy":"validation","validationCode":"Executor ex = interceptor.getDefaultExecutor(context.getBeanFactory());\nif (ex == null) {\n    ThreadPoolTaskExecutor t = new ThreadPoolTaskExecutor();\n    t.initialize();\n    interceptor.setExecutor(t);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always provide an Executor via AsyncConfigurer.getAsyncExecutor() or setExecutor(...).","Keep a 'taskExecutor' bean in the context as a reliable default.","If overriding getDefaultExecutor, preserve the SimpleAsyncTaskExecutor fallback."],"tags":["spring-aop","async","executor","configuration"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}