{"record":{"id":"72a4cfc445c7a22f","repo":"quarkusio/quarkus","slug":"unhandled-async-return-type","errorCode":null,"errorMessage":"Unhandled async return type","messagePattern":"Unhandled async return type","errorType":"exception","errorClass":"CacheException","httpStatus":null,"severity":"error","filePath":"extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/CacheInterceptor.java","lineNumber":245,"sourceCode":"        }\n        if (CompletionStage.class.isAssignableFrom(returnType)) {\n            return ReturnType.CompletionStage;\n        }\n        return ReturnType.NonAsync;\n    }\n\n    protected Uni<?> asyncInvocationResultToUni(Object invocationResult, ReturnType returnType) {\n        if (returnType == ReturnType.Uni) {\n            return (Uni<?>) invocationResult;\n        } else if (returnType == ReturnType.CompletionStage) {\n            return Uni.createFrom().completionStage(new Supplier<>() {\n                @Override\n                public CompletionStage<?> get() {\n                    return (CompletionStage<?>) invocationResult;\n                }\n            });\n        } else {\n            throw new CacheException(new IllegalStateException(UNHANDLED_ASYNC_RETURN_TYPE_MSG));\n        }\n    }\n\n    protected Object createAsyncResult(Uni<Object> cacheValue, ReturnType returnType) {\n        if (returnType == ReturnType.Uni) {\n            return cacheValue;\n        }\n        if (returnType == ReturnType.CompletionStage) {\n            return cacheValue.subscribeAsCompletionStage();\n        }\n        throw new CacheException(new IllegalStateException(UNHANDLED_ASYNC_RETURN_TYPE_MSG));\n    }\n\n    protected enum ReturnType {\n        NonAsync,\n        Uni,\n        CompletionStage\n    }","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/cache/runtime/src/main/java/io/quarkus/cache/runtime/CacheInterceptor.java#L227-L263","documentation":"asyncInvocationResultToUni converts an intercepted method's result into a Uni for caching. It supports Uni and CompletionStage return types; if it is invoked with any other ReturnType (i.e. NonAsync slipped through), it throws CacheException wrapping an IllegalStateException. This normally indicates an internal dispatch bug rather than user error.","triggerScenarios":"A cached method whose declared return type was classified as NonAsync by determineReturnType but still routed through the async conversion path — practically only reachable via subclassing CacheInterceptor or inconsistent classification (e.g. exotic return types like Uni subtypes handled inconsistently across custom interceptor subclasses).","commonSituations":"Custom interceptor subclasses overriding determineReturnType or the invocation flow; framework-level regressions after upgrading Quarkus; Kotlin suspend/CompletableFuture variants misclassified.","solutions":["Verify the cached method returns exactly Uni or CompletionStage (or a plain, non-async type) and nothing exotic.","If you subclass CacheInterceptor, ensure determineReturnType and asyncInvocationResultToUni stay consistent.","If hit without custom code, report it as a Quarkus bug with the method signature and version."],"exampleFix":"// before\n@CacheResult(cacheName = \"x\")\npublic SomeReactiveType get(String id) { ... } // unsupported async type\n\n// after\n@CacheResult(cacheName = \"x\")\npublic Uni<SomeType> get(String id) { ... }","handlingStrategy":"validation","validationCode":"Class<?> rt = cachedMethod.getReturnType();\nif (!io.smallrye.mutiny.Uni.class.isAssignableFrom(rt)\n        && !java.util.concurrent.CompletionStage.class.isAssignableFrom(rt)\n        && isAsyncDispatch(rt)) {\n    throw new IllegalStateException(\"Return Uni or CompletionStage for async caching\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict cached methods to Uni, CompletionStage, or plain return types","Avoid exotic reactive wrappers (Mono, Maybe) on @CacheResult methods","Keep interceptor subclasses consistent with determineReturnType"],"tags":["quarkus","cache","async","uni","internal"],"backgroundTag":"unhandled-async-return-type","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}