{"record":{"id":"67290bfec6bfdcb9","repo":"quarkusio/quarkus","slug":"cannot-handle-wildcard-type","errorCode":null,"errorMessage":"Cannot handle wildcard type ","messagePattern":"Cannot handle wildcard type ","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java","lineNumber":1149,"sourceCode":"    protected static String toClassName(Type indexType, ClassInfo currentClass, ClassInfo actualEndpointClass,\n            IndexView indexView) {\n        switch (indexType.kind()) {\n            case VOID:\n                return \"void\";\n            case CLASS:\n                return indexType.asClassType().name().toString();\n            case PRIMITIVE:\n                return indexType.asPrimitiveType().primitive().name().toLowerCase(Locale.ENGLISH);\n            case PARAMETERIZED_TYPE:\n                return indexType.asParameterizedType().name().toString();\n            case ARRAY:\n                return indexType.asArrayType().name().toString();\n            case WILDCARD_TYPE:\n                WildcardType wildcardType = indexType.asWildcardType();\n                Type extendsBound = wildcardType.extendsBound();\n                if (extendsBound.name().equals(OBJECT)) {\n                    // this is a super bound type that we don't support\n                    throw new RuntimeException(\"Cannot handle wildcard type \" + indexType);\n                }\n                // this is an extend bound type, so we just user the bound\n                return wildcardType.name().toString();\n            case TYPE_VARIABLE:\n                TypeVariable typeVariable = indexType.asTypeVariable();\n                if (typeVariable.bounds().isEmpty()) {\n                    return Object.class.getName();\n                }\n\n                return toClassName(resolveTypeVariable(typeVariable, currentClass, actualEndpointClass, indexView),\n                        currentClass, actualEndpointClass, indexView);\n            default:\n                throw new RuntimeException(\"Unknown parameter type \" + indexType);\n        }\n    }\n\n    private static Type resolveTypeVariable(TypeVariable typeVariable, ClassInfo currentClass, ClassInfo actualEndpointClass,\n            IndexView indexView) {","sourceCodeStart":1131,"sourceCodeEnd":1167,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java#L1131-L1167","documentation":"When converting indexed types to class names, EndpointIndexer.toClassName cannot represent a wildcard type with an unbounded/Object bound (e.g. ? or List<?>). Only wildcards with a meaningful extends bound are supported (the bound is used instead). It throws a RuntimeException, typically surfaced wrapped by error 3383.","triggerScenarios":"A resource method signature uses an unbounded wildcard generic such as List<?>, Map<String,?>, or a parameter/return type of ? with no extends bound, and Quarkus indexes the endpoint.","commonSituations":"Generic helper signatures reused in resource methods; returning ResponseEntity<List<?>> style types; copy-pasting repository/DAO generic types into endpoints.","solutions":["Replace the unbounded wildcard with a concrete type (e.g. List<String> instead of List<?>)","Use an explicit extends bound (e.g. List<? extends Number>) if subtype flexibility is needed","Move the wildcard-typed logic out of the endpoint signature into internal code with concrete types"],"exampleFix":"// before\n@GET\npublic List<?> list() { ... }\n// after\n@GET\npublic List<String> list() { ... }","handlingStrategy":"type-guard","validationCode":"static <T> Class<T> requireConcrete(java.lang.reflect.Type t) {\n    if (t instanceof ParameterizedType pt) {\n        for (java.lang.reflect.Type arg : pt.getActualTypeArguments()) {\n            if (arg instanceof WildcardType wt\n                && (wt.getUpperBounds().length == 0 || wt.getUpperBounds()[0] == Object.class)\n                && wt.getLowerBounds().length == 0)\n                throw new IllegalArgumentException(\"Unbounded wildcard not allowed: \" + t);\n            requireConcrete(arg);\n        }\n    }\n    return null;\n}","typeGuard":"static boolean isSupportedEndpointType(java.lang.reflect.Type t) {\n    if (t instanceof WildcardType wt) {\n        return wt.getUpperBounds().length > 0 && wt.getUpperBounds()[0] != Object.class;\n    }\n    if (t instanceof ParameterizedType pt) {\n        return java.util.Arrays.stream(pt.getActualTypeArguments())\n            .allMatch(MyChecks::isSupportedEndpointType);\n    }\n    return !(t instanceof WildcardType);\n}","tryCatchPattern":null,"preventionTips":["Avoid unbounded wildcards (List<?>, Map<?,?>) in endpoint signatures","Prefer concrete types or explicit extends bounds for generics in REST APIs","Keep generic flexibility in internal service code, not the REST layer","Compile endpoints early with quarkus:dev to catch indexing failures"],"tags":["quarkus","resteasy-reactive","generics","wildcard","deployment"],"backgroundTag":"unsupported-generic-type","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"}