{"record":{"id":"470f31641974aca8","repo":"quarkusio/quarkus","slug":"cdi-event-payload-cannot-contain-unresolved-type-v","errorCode":null,"errorMessage":"CDI event payload cannot contain unresolved type variable; found type: ","messagePattern":"CDI event payload cannot contain unresolved type variable; found type: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java","lineNumber":248,"sourceCode":"        }\n        if (Types.containsTypeVariable(resolvedType)) {\n            /*\n             * Examining the hierarchy of the specified type did not help. This may still be one of the cases when combining the\n             * event type and the specified\n             * type reveals the actual values for type variables. Let's try that.\n             */\n            Type canonicalEventType = Types.getCanonicalType(runtimeType);\n            TypeResolver objectTypeResolver = new EventObjectTypeResolverBuilder(\n                    injectionPointTypeHierarchy.getResolver().getResolvedTypeVariables(),\n                    new HierarchyDiscovery(canonicalEventType).getResolver().getResolvedTypeVariables()).build();\n            resolvedType = objectTypeResolver.resolveType(canonicalEventType);\n        }\n        /*\n         * If the runtime type of the event object still contains an unresolved type variable,\n         * the container must throw an IllegalArgumentException.\n         */\n        if (Types.containsTypeVariable(resolvedType)) {\n            throw new IllegalArgumentException(\n                    \"CDI event payload cannot contain unresolved type variable; found type: \" + resolvedType);\n        }\n        return resolvedType;\n    }\n\n    private void handleExceptions(ObserverExceptionHandler handler) {\n        List<Throwable> handledExceptions = handler.getHandledExceptions();\n        if (!handledExceptions.isEmpty()) {\n            CompletionException exception = null;\n            if (handledExceptions.size() == 1) {\n                exception = new CompletionException(handledExceptions.get(0));\n            } else {\n                exception = new CompletionException(null);\n            }\n            // always add exceptions into suppressed\n            for (Throwable handledException : handledExceptions) {\n                exception.addSuppressed(handledException);\n            }","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java#L230-L266","documentation":"When firing a CDI event, ArC must compute the concrete event type to match observers. If, after resolving against the injection point type hierarchy and the runtime class hierarchy, the type still contains an unresolved type variable, the container throws IllegalArgumentException per the CDI specification. This means observers could never reliably receive the event.","triggerScenarios":"Calling event.fire(x) or fireAsync() where the runtime class of the payload is a parameterized type with unbound variables, e.g. firing an instance of a generic class ListWrapper<T> from generic code where T was never bound.","commonSituations":"Firing generic payloads like Result<T> or Wrapper<T> from generic service methods; firing events inside generic repository base classes; payload classes that extend generic superclasses without fixing the type parameters.","solutions":["Fire a payload whose runtime type is fully concrete (no open type variables)","Create a concrete subclass of the generic payload (e.g. new StringResult() extends Result<String>) so the type variables are bound","Pass a fully resolved type when obtaining the Event so the resolver has type information to work with","Refactor the payload to be non-generic or use a dedicated concrete event record per payload type"],"exampleFix":"// before\nclass Publisher<T> {\n  @Inject Event<Result<T>> event;\n  void publish(T value) { event.fire(new Result<>(value)); } // runtime type Result<T> unresolved\n}\n// after\nclass StringPublisher {\n  @Inject Event<Result<String>> event;\n  void publish(String value) { event.fire(new Result<>(value)); }\n}","handlingStrategy":"validation","validationCode":"static void assertConcretePayload(Object event) {\n    if (io.quarkus.arc.impl.Types.containsTypeVariable(event.getClass())) {\n        throw new IllegalArgumentException(\"Event payload has unresolved type variables: \" + event.getClass());\n    }\n}\n// call before event.fire(x)","typeGuard":"static boolean isFireable(Object payload) {\n    return !io.quarkus.arc.impl.Types.containsTypeVariable(payload.getClass());\n}","tryCatchPattern":"try {\n    event.fire(payload);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"CDI event payload cannot contain unresolved type variable\")) {\n        log.errorf(\"Payload %s is generic; use a concrete subclass\", payload.getClass());\n    }\n    throw e;\n}","preventionTips":["Prefer concrete event records/classes (e.g. OrderCreated) over generic wrappers (Result<T>) as payloads","If payloads must be generic, create named concrete subclasses to fix the type parameters","Avoid firing events from generic base classes where T is unbound at runtime"],"tags":["cdi","generics","arc","events"],"backgroundTag":"unresolved-type-variable","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"}