Common Issues
1. java.lang.IllegalStateException - No thread-bound request found
Case 1
We have an HTTP endpoint that processes a payment and then asynchronously sends an SMS using a method annotated with @Async. Inside the async method, some values are accessed from the HttpServletRequest or request-scoped beans.
Error Message:
java.lang.IllegalStateException: No thread-bound request found:
Are you referring to request attributes outside of an actual web request,
or processing a request outside of the originally receiving thread?
If you are actually operating within a web request and still receive this message,
your code is probably running outside of DispatcherServlet:
In this case, use RequestContextListener or RequestContextFilter to expose the current request.Root Cause:
Spring manages the HTTP request lifecycle using thread-bound context. That means request-related objects (like HttpServletRequest, RequestAttributes, or beans scoped as request) are available only within the thread that handled the request.
When we use @Async, the annotated method executes in a separate thread, which does not have access to the original thread’s request context. So any attempt to read request attributes (like headers, parameters, or session data) from the async method will result in this exception.
Solution:
Option 1: Pass Required Data Explicitly
The recommended and safest approach is to extract any necessary values from the request before calling the async method, and pass them as method arguments.
Option 2: Register a RequestContextListener
If we absolutely need access to the request context in the async thread, register a RequestContextListener in our configuration:
Note: Even with this, it's not always reliable to depend on request context in async threads, especially under heavy load or across thread pools.
Option 3: Use a RequestContextFilter (Alternative to Listener)
If our application uses filters and we want to ensure consistent behavior across threads, we can use RequestContextFilter:
Case 2
We are using @Asyn method which runs after main thread is over. This method calls another api and uses private final HttpServletRequest request but request is no more available as main thread is exited.
The issue arises because HttpServletRequest is inherently tied to the main thread's lifecycle in Java web applications. Once the main thread exits, the HttpServletRequest object is no longer valid or accessible.
When using @Async methods in Spring Boot, the code runs in a different thread than the one handling the HTTP request. To solve this issue, you need to extract the necessary information from HttpServletRequest before the main thread exits and pass it explicitly to the @Async method.
1. Clone the Request Data
Manually copy the relevant information from the HttpServletRequest before invoking the @Async method. We can store the information in a Map or a custom object.
Example:
Main Thread
Async Service
2. Use a ThreadLocal for Propagation
Use a ThreadLocal to propagate the HttpServletRequest to the async thread. We can copy the data into a ThreadLocal before invoking the @Async method.
Utility Class
Main Thread
Async Service
Caution: Using ThreadLocal with @Async should be done carefully, as Spring may use thread pooling for async tasks. Always clear the ThreadLocal to avoid memory leaks or incorrect data propagation.
3. Use RequestContextHolder
Spring provides RequestContextHolder for accessing the current HttpServletRequest. However, we must configure Spring to allow request context propagation to async threads.
Configuration
Enable request context propagation in Spring Boot by setting the following property in application.properties:
Access Request in Async Method
2. ScopeNotActiveException in Async/Executor Threads
The error we're encountering arises because the @RequestScope beans in Spring are tied to the HTTP request lifecycle. When using ExecutorService to execute tasks asynchronously, the task runs in a different thread from the original HTTP request thread, and the RequestScope is not active in the new thread.
Why This Happens
Request Scope Lifecycle:
Beans annotated with
@RequestScopeare bound to the lifecycle of the HTTP request.When the original HTTP thread finishes processing the request, the request scope is destroyed.
Asynchronous Threads:
When we submit tasks to
ExecutorService, these tasks are executed in separate threads. These threads are independent of the HTTP request and do not have access to theRequestScope.
Solutions
1. Use Scoped Proxies
Spring allows us to use a scoped proxy for @RequestScope beans. This creates a proxy object that resolves the actual bean at runtime, ensuring the correct RequestScope context is used.
Example:
If our bean is already annotated with @RequestScope:
2. Pass Contextual Information
Instead of relying on @RequestScope beans in an asynchronous task, pass the required request-scoped data as method parameters. Extract necessary data in the controller layer and pass it to the service or task.
Example:
3. Use @Async with Context Propagation
The @Async annotation in Spring can manage scoped beans if properly configured with context propagation. We can use libraries like Spring Cloud Sleuth or TaskDecorator to propagate the request context.
Example with
TaskDecorator:This setup propagates the request context into asynchronous threads.
4. Avoid Using @RequestScope for Long-Lived Tasks
If our task requires data for processing that might outlive the request, consider fetching or caching the required data before starting the asynchronous task.
Last updated