{"record":{"id":"43e184f07f7780ad","repo":"quarkusio/quarkus","slug":"an-existing-cached-value-type-does-not-match-the-r","errorCode":null,"errorMessage":"An existing cached value type does not match the requested type","messagePattern":"An existing cached value type does not match the requested type","errorType":"exception","errorClass":"CacheException","httpStatus":null,"severity":"error","filePath":"extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java","lineNumber":192,"sourceCode":"    public <V> CompletableFuture<V> getIfPresent(Object key) {\n        Objects.requireNonNull(key, NULL_KEYS_NOT_SUPPORTED_MSG);\n        CompletableFuture<Object> existingCacheValue = cache.getIfPresent(key);\n\n        if (existingCacheValue == null) {\n            return null;\n        } else {\n            LOGGER.tracef(\"Key [%s] found in cache [%s]\", key, cacheInfo.name);\n\n            // cast, but still throw the CacheException in case it fails\n            return unwrapCacheValueOrThrowable(existingCacheValue)\n                    .thenApply(new Function<>() {\n                        @SuppressWarnings(\"unchecked\")\n                        @Override\n                        public V apply(Object value) {\n                            try {\n                                return (V) value;\n                            } catch (ClassCastException e) {\n                                throw new CacheException(\"An existing cached value type does not match the requested type\", e);\n                            }\n                        }\n                    });\n\n        }\n    }\n\n    /**\n     * Returns a {@link CompletableFuture} holding the cache value identified by {@code key}, obtaining that value from\n     * {@code valueLoader} if necessary. The value computation is done synchronously on the calling thread and the\n     * {@link CompletableFuture} is immediately completed before being returned.\n     *\n     * @param key cache key\n     * @param valueLoader function used to compute the cache value if {@code key} is not already associated with a value\n     * @return a {@link CompletableFuture} holding the cache value\n     * @throws CacheException if an exception is thrown during the cache value computation\n     */\n    private <K, V> CompletableFuture<Object> getFromCaffeine(K key, Function<K, V> valueLoader) {","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java#L174-L210","documentation":"Thrown by CaffeineCacheImpl when a value already stored in the cache cannot be cast to the generic type V requested by the caller via the Cache API (the cache stores values as Object). This happens when the same cache name is used with different value types, e.g. after changing a method's return type or calling put() with a mismatched type. The ClassCastException is wrapped in a CacheException to give a clearer message.","triggerScenarios":"Calling get/getAsync/put on a Caffeine-backed cache whose existing entries were stored under a different value type; the unchecked cast (V) value throws ClassCastException.","commonSituations":"Reusing a cache name for two methods with different return types; changing a cached method's return type while old entries persist; deserialization/classloader changes across hot redeployment in dev mode.","solutions":["Use a distinct @CacheName/cache name for each value type","Clear/invalidate the cache (or restart the app) so stale entries of the old type are removed","Ensure the cached method's return type and all callers agree on one type"],"exampleFix":"// before\n@CacheName(\"myCache\")\npublic String getName(long id) { ... }\npublic User getUser(long id) { ... } // same cache, different type\n// after\n@CacheName(\"nameCache\")\npublic String getName(long id) { ... }\n@CacheName(\"userCache\")\npublic User getUser(long id) { ... }","handlingStrategy":"type-guard","validationCode":"// store one type per cache name and verify before reads\nObject existing = cache.get(key, k -> null);\nif (existing != null && !(existing instanceof ExpectedType)) {\n    cache.invalidate(key).await().indefinitely();\n}","typeGuard":"boolean isExpectedType(Object value) {\n    return value instanceof ExpectedType;\n}","tryCatchPattern":"try {\n    V value = cache.get(key, loader);\n} catch (CacheException e) {\n    if (e.getCause() instanceof ClassCastException) {\n        cache.invalidate(key).await().indefinitely();\n        value = cache.get(key, loader);\n    } else { throw e; }\n}","preventionTips":["One cache name per value type","Invalidate stale entries after changing a cached method's return type","Restart or clear caches after dev-mode hot reloads that change types"],"tags":["cache","caffeine","classcast"],"backgroundTag":"cache-value-type-mismatch","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}