{"record":{"id":"e19aa3e5e0f7cfe3","repo":"Netflix/Hystrix","slug":"request-caching-is-not-available-maybe-you-need-t","errorCode":null,"errorMessage":"Request caching is not available. Maybe you need to initialize the HystrixRequestContext?","messagePattern":"Request caching is not available\\. Maybe you need to initialize the HystrixRequestContext\\?","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestCache.java","lineNumber":104,"sourceCode":"                c = existing;\n            }\n        }\n        return c;\n    }\n\n    /**\n     * Retrieve a cached Future for this request scope if a matching command has already been executed/queued.\n     * \n     * @return {@code Future<T>}\n     */\n    // suppressing warnings because we are using a raw Future since it's in a heterogeneous ConcurrentHashMap cache\n    @SuppressWarnings({ \"unchecked\" })\n    /* package */<T> HystrixCachedObservable<T> get(String cacheKey) {\n        ValueCacheKey key = getRequestCacheKey(cacheKey);\n        if (key != null) {\n            ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);\n            if (cacheInstance == null) {\n                throw new IllegalStateException(\"Request caching is not available. Maybe you need to initialize the HystrixRequestContext?\");\n            }\n            /* look for the stored value */\n            return (HystrixCachedObservable<T>) cacheInstance.get(key);\n        }\n        return null;\n    }\n\n    /**\n     * Put the Future in the cache if it does not already exist.\n     * <p>\n     * If this method returns a non-null value then another thread won the race and it should be returned instead of proceeding with execution of the new Future.\n     * \n     * @param cacheKey\n     *            key as defined by {@link HystrixCommand#getCacheKey()}\n     * @param f\n     *            Future to be cached\n     * \n     * @return null if nothing else was in the cache (or this {@link HystrixCommand} does not have a cacheKey) or previous value if another thread beat us to adding to the cache","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/Netflix/Hystrix/blob/5ce3bc58c38e7ca60ef2fe0e516e390e294ad941/hystrix-core/src/main/java/com/netflix/hystrix/HystrixRequestCache.java#L86-L122","documentation":"HystrixRequestCache.get() looks up the per-request cache map via a HystrixRequestVariable backed by HystrixRequestContext; when a cacheKey exists but requestVariableForCache.get(...) returns null, the HystrixRequestContext was never initialized for this thread, so request caching cannot work and IllegalStateException is thrown with the hint 'Maybe you need to initialize the HystrixRequestContext?'.","triggerScenarios":"Executing a command that implements getCacheKey() (or a collapser) on a thread whose HystrixRequestContext was never initialized — e.g. calling queue()/execute()/toObservable() without wrapping in HystrixRequestContext.initializeContext(), or on a non-web thread (scheduler, @Async executor, grpc netty thread) that never ran the init.","commonSituations":"First use of request caching in a batch job or main() without the context; async/thread-pool hopping losing the thread-local context (HystrixRequestContext is ThreadLocal, not InheritableThreadLocal); servlet filters not installed; unit tests executing commands without shutdown()/context setup.","solutions":["Wrap the request lifecycle: HystrixRequestContext ctx = HystrixRequestContext.initializeContext(); try { ...commands... } finally { ctx.shutdown(); }","Install a servlet Filter (or framework interceptor) that initializes/shuts down the context per request","For thread hopping, propagate the context explicitly or implement HystrixConcurrencyStrategy.wrapCallable to carry it","If request caching is unwanted, remove the getCacheKey() override so the cache path is skipped"],"exampleFix":"// before\nHystrixRequestContext ctx = HystrixRequestContext.initializeContext();\n// after (missing)\n// missing\nHystrixRequestContext ctx = HystrixRequestContext.initializeContext();\ntry {\n  String a = new GetOrderCommand(id).execute();\n  String b = new GetOrderCommand(id).execute(); // served from cache\n} finally {\n  ctx.shutdown();\n}","handlingStrategy":"validation","validationCode":"if (command.getCacheKey() != null && !HystrixRequestContext.isCurrentThreadInitialized()) {\n  // initialize or skip request caching\n  HystrixRequestContext.initializeContext(); // remember to shutdown later\n}","typeGuard":"null","tryCatchPattern":"catch (IllegalStateException e) { if (e.getMessage().contains(\"initialize the HystrixRequestContext\")) { try (HystrixRequestContext ctx = HystrixRequestContext.initializeContext()) { /* retry command */ } } } — note initializeContext returns the context; shutdown in finally.","preventionTips":["Always wrap request lifecycles with initializeContext()/shutdown() (servlet filter or interceptor)","Propagate the context to child threads explicitly","Return null from getCacheKey() when request caching is not needed"],"tags":["java","hystrix","request-context","caching","thread-local"],"backgroundTag":null,"analyzedSha":"5ce3bc58c38e7ca60ef2fe0e516e390e294ad941","analyzedAt":"2026-08-14T10:55:35.600Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}