Async not working for method having return type void
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
@Async can be used on a void method in Spring, so the return type is usually not the real problem. When an async void method appears to run synchronously or not run at all, the cause is almost always proxying, configuration, or error visibility.
Core Sections
void is allowed, but it changes observability
Spring supports async methods returning void, Future, CompletableFuture, and related async types. A void method is fire-and-forget: the caller does not receive a handle for completion, result, or failure.
That method can run asynchronously, but only if Spring is actually intercepting the call through an async proxy.
The two requirements people miss
First, async support must be enabled. Second, the method must be called through a Spring-managed bean, not through self-invocation inside the same class.
Now consider this service:
generate() calls sendAsync() on this, so the call never passes through Spring's proxy. The annotation is effectively bypassed. Move the async method to another bean, or inject the proxied bean and call through that.
Why void methods make debugging harder
With CompletableFuture, the caller can wait, chain, or inspect failures. With void, exceptions are not returned to the caller. If your async code throws, the error may only appear in logs, or nowhere obvious if you did not configure an uncaught exception handler.
That setup does not make void wrong, but it makes failures visible.
When to prefer CompletableFuture
If the caller needs to know whether the task finished, failed, or produced a value, void is the wrong interface.
That makes testing easier and avoids the "it did not work" class of bug where the real issue was simply that the caller had no way to observe the result.
A quick checklist when @Async seems broken
If a void async method looks synchronous, check these items in order:
@EnableAsyncexists in configuration.- The method is
public. - The bean is managed by Spring.
- The call comes from another bean, not from the same instance.
- The application has an executor or logs thread names so you can confirm offloading.
Common Pitfalls
- Blaming the
voidreturn type when the real problem is missing@EnableAsync. - Calling the async method from another method in the same class and bypassing the proxy.
- Expecting thrown exceptions to surface in the caller when using fire-and-forget
void. - Forgetting to configure an executor and then struggling to verify which thread ran the work.
- Using
voidwhen the business flow actually needs completion status or a returned value.
Summary
- A Spring
@Asyncmethod can returnvoid; that alone does not disable async behavior. - The call must pass through a Spring proxy, which means self-invocation does not work.
- '
voidmethods are harder to observe because completion and failure are not returned.' - Configure
@EnableAsync, a real executor, and exception handling before debugging deeper. - Use
CompletableFuturewhen the caller needs a result or reliable failure propagation.

