quarkusio/quarkus · error · CacheException

An existing cached value type does not match the requested t

Error message

An existing cached value type does not match the requested type

What it means

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.

Source

Thrown at extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/caffeine/CaffeineCacheImpl.java:192

    public <V> CompletableFuture<V> getIfPresent(Object key) {
        Objects.requireNonNull(key, NULL_KEYS_NOT_SUPPORTED_MSG);
        CompletableFuture<Object> existingCacheValue = cache.getIfPresent(key);

        if (existingCacheValue == null) {
            return null;
        } else {
            LOGGER.tracef("Key [%s] found in cache [%s]", key, cacheInfo.name);

            // cast, but still throw the CacheException in case it fails
            return unwrapCacheValueOrThrowable(existingCacheValue)
                    .thenApply(new Function<>() {
                        @SuppressWarnings("unchecked")
                        @Override
                        public V apply(Object value) {
                            try {
                                return (V) value;
                            } catch (ClassCastException e) {
                                throw new CacheException("An existing cached value type does not match the requested type", e);
                            }
                        }
                    });

        }
    }

    /**
     * Returns a {@link CompletableFuture} holding the cache value identified by {@code key}, obtaining that value from
     * {@code valueLoader} if necessary. The value computation is done synchronously on the calling thread and the
     * {@link CompletableFuture} is immediately completed before being returned.
     *
     * @param key cache key
     * @param valueLoader function used to compute the cache value if {@code key} is not already associated with a value
     * @return a {@link CompletableFuture} holding the cache value
     * @throws CacheException if an exception is thrown during the cache value computation
     */
    private <K, V> CompletableFuture<Object> getFromCaffeine(K key, Function<K, V> valueLoader) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use a distinct @CacheName/cache name for each value type
  2. Clear/invalidate the cache (or restart the app) so stale entries of the old type are removed
  3. Ensure the cached method's return type and all callers agree on one type

Example fix

// before
@CacheName("myCache")
public String getName(long id) { ... }
public User getUser(long id) { ... } // same cache, different type
// after
@CacheName("nameCache")
public String getName(long id) { ... }
@CacheName("userCache")
public User getUser(long id) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

// store one type per cache name and verify before reads
Object existing = cache.get(key, k -> null);
if (existing != null && !(existing instanceof ExpectedType)) {
    cache.invalidate(key).await().indefinitely();
}

Type guard

boolean isExpectedType(Object value) {
    return value instanceof ExpectedType;
}

Try / catch

try {
    V value = cache.get(key, loader);
} catch (CacheException e) {
    if (e.getCause() instanceof ClassCastException) {
        cache.invalidate(key).await().indefinitely();
        value = cache.get(key, loader);
    } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/43e184f07f7780ad. Report an issue: GitHub.