{"record":{"id":"746e1225163154b5","repo":"quarkusio/quarkus","slug":"invalid-type-variable-in-signature-signature-a","errorCode":null,"errorMessage":"Invalid type variable in signature: ${signature} at position ${i}","messagePattern":"Invalid type variable in signature: (.+?) at position (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/types/TypeSignatureParser.java","lineNumber":60,"sourceCode":"                    break LOOP;\n                case 'S':\n                    ret = short.class;\n                    break LOOP;\n                case 'Z':\n                    ret = boolean.class;\n                    break LOOP;\n                case 'V':\n                    ret = void.class;\n                    break LOOP;\n                // ClassTypeSignature\n                case 'L':\n                    ret = parseReference();\n                    break LOOP;\n                // TypeVariableSignature\n                case 'T':\n                    // Stef has come to the conclusion that because TypeVariable depends on the GenericDeclaration that defined them, which is lacking\n                    // in signatures unless we have access to the current context, we should not support them\n                    throw new IllegalArgumentException(\n                            \"Invalid type variable in signature: \" + new String(chars) + \" at position \" + i);\n                case '[':\n                    arrayCount++;\n                    break;\n                default:\n                    throw new IllegalArgumentException(\n                            \"Invalid signature char: \" + c + \" in \" + new String(chars) + \" at position \" + i);\n            }\n        } while (true);\n        if (arrayCount > 0) {\n            if (ret instanceof Class) {\n                Class<?> retClass = (Class<?>) ret;\n                if (retClass.isPrimitive()) {\n                    // load [I or [[I\n                    return loadClass(new String(chars, start, i - start));\n                }\n                // get the [L part and the name out of the class\n                return loadClass(new String(chars, start, arrayCount + 1) + retClass.getName() + \";\");","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/util/types/TypeSignatureParser.java#L42-L78","documentation":"TypeSignatureParser parses JVM field/method type signature strings (e.g. 'Ljava/util/List<Ljava/lang/String;>;'). Type variable signatures ('T...;') are deliberately unsupported because java.lang.reflect.TypeVariable requires the GenericDeclaration context, which is absent from the raw signature. Hitting 'T' in parseType throws this IllegalArgumentException naming the signature and position.","triggerScenarios":"Parsing a signature string containing a type variable reference, e.g. from a generic class method like '(TT;)TT;' or a field 'TT;', passed to TypeSignatureParser.parse or parseReference->parseType.","commonSituations":"Reflecting on generic classes whose members reference the class's own type parameters; generating signatures from generic code and feeding them to RESTEasy Reactive type introspection (e.g. generic resource classes or MessageBodyReader resolution).","solutions":["Replace type variables with concrete types: specialize the class/method (e.g. use a subclass with concrete type arguments instead of raw generic ones)","Resolve the TypeVariable manually against the declaring GenericDeclaration before parsing","Pre-process the signature to substitute 'TName;' with the erased or actual type before calling the parser","Avoid parsing signatures of raw generic members; operate on ParameterizedType from a concrete subclass via getGenericSuperclass"],"exampleFix":"// before\nTypeSignatureParser.parse(\"(TT;)TT;\"); // throws\n// after\nclass StringResource extends GenericResource<String> {}\nType t = StringResource.class.getGenericSuperclass(); // concrete ParameterizedType","handlingStrategy":"try-catch","validationCode":"static boolean signatureHasTypeVariable(String sig) {\n    return sig != null && sig.contains(\"T\") && Pattern.compile(\"(^|[^A-Z])T[A-Za-z0-9_$]*;\").matcher(sig).find();\n}\n// reject/guard before calling TypeSignatureParser.parse","typeGuard":null,"tryCatchPattern":"try {\n    Type t = TypeSignatureParser.parse(signature);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Invalid type variable\")) {\n    throw new UnsupportedOperationException(\"Resolve type variables against a concrete subclass first\");\n    } else throw e;\n}","preventionTips":["Avoid parsing signatures of raw generic members; specialize with concrete type arguments first","Resolve TypeVariables via getGenericSuperclass on a concrete subclass before signature work","Document that the signature parser does not support 'T...;' tokens","Filter out methods/fields referencing type parameters before introspection"],"tags":["generics","reflection","signature-parsing"],"backgroundTag":"unsupported-type-variable-signature","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"}