{"record":{"id":"d7299c0afc578757","repo":"spring-projects/spring-framework","slug":"invalid-method-signature-unable-to-resolve-type","errorCode":null,"errorMessage":"Invalid method signature: unable to resolve type [{parameterTypeName}] for argument {i}. Root cause: {ex}","messagePattern":"Invalid method signature: unable to resolve type \\[(.+?)\\] for argument (.+?)\\. Root cause: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/BeanUtils.java","lineNumber":479,"sourceCode":"\t\telse if (startParen == -1 && endParen > -1) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid method signature '\" + signature +\n\t\t\t\t\t\"': expected opening '(' for args list\");\n\t\t}\n\t\telse if (startParen == -1) {\n\t\t\treturn findMethodWithMinimalParameters(clazz, signature);\n\t\t}\n\t\telse {\n\t\t\tString methodName = signature.substring(0, startParen);\n\t\t\tString[] parameterTypeNames =\n\t\t\t\t\tStringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));\n\t\t\tClass<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];\n\t\t\tfor (int i = 0; i < parameterTypeNames.length; i++) {\n\t\t\t\tString parameterTypeName = parameterTypeNames[i].trim();\n\t\t\t\ttry {\n\t\t\t\t\tparameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());\n\t\t\t\t}\n\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Invalid method signature: unable to resolve type [\" +\n\t\t\t\t\t\t\tparameterTypeName + \"] for argument \" + i + \". Root cause: \" + ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn findMethod(clazz, methodName, parameterTypes);\n\t\t}\n\t}\n\n\n\t/**\n\t * Retrieve the JavaBeans {@code PropertyDescriptor}s of a given class.\n\t * @param clazz the Class to retrieve the PropertyDescriptors for\n\t * @return an array of {@code PropertyDescriptors} for the given class\n\t * @throws BeansException if PropertyDescriptor look fails\n\t */\n\tpublic static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {\n\t\treturn CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors();\n\t}\n","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java#L461-L497","documentation":"Thrown as IllegalArgumentException by resolveSignature at BeanUtils.java:479 when a parameter type name inside the signature cannot be resolved to a Class via ClassUtils.forName(parameterTypeName, classLoader). It names the offending type, the argument index, and the root cause (typically ClassNotFoundException). All argument types must be fully resolvable on the target's classloader.","triggerScenarios":"Calling resolveSignature(\"doStuff(com.missing.Type)\", clazz) where com.missing.Type is not on the classpath; using unqualified type names that ClassUtils.forName cannot resolve (it expects fully-qualified names, with limited primitive/array shortcuts); passing a type from another module/classloader not visible here.","commonSituations":"Config-driven method invocation referencing types not present at runtime; refactor that renamed/moved a class without updating the string signature; classloader isolation in app servers/OSGi; using short names like 'String' instead of 'java.lang.String' (forName does not import packages).","solutions":["Use the fully-qualified type name, e.g. \"doStuff(java.lang.String, java.lang.Integer)\".","Ensure the referenced type's JAR/class is on the runtime classpath of the resolving classloader.","After a rename/refactor, update all string-based method signatures.","If short names are desired, resolve them to FQCNs yourself before calling resolveSignature."],"exampleFix":"// before\nMethod m = BeanUtils.resolveSignature(\"doStuff(String, Integer)\", clazz);\n\n// after\nMethod m = BeanUtils.resolveSignature(\"doStuff(java.lang.String, java.lang.Integer)\", clazz);","handlingStrategy":"validation","validationCode":"// Validate each type name resolves on the target classloader first\nString sig = \"doStuff(java.lang.String, java.lang.Integer)\";\nfor (String t : sig.substring(sig.indexOf('(')+1, sig.indexOf(')')).split(\",\")) {\n    ClassUtils.forName(t.trim(), clazz.getClassLoader());\n}\nBeanUtils.resolveSignature(sig, clazz);","typeGuard":"static boolean allTypesResolvable(String sig, ClassLoader cl) {\n    String args = sig.substring(sig.indexOf('(')+1, sig.indexOf(')'));\n    for (String t : args.split(\",\")) {\n        if (t.isBlank()) continue;\n        try { ClassUtils.forName(t.trim(), cl); }\n        catch (Throwable e) { return false; }\n    }\n    return true;\n}","tryCatchPattern":"try {\n    BeanUtils.resolveSignature(sig, clazz);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage().contains(\"unable to resolve type\")) {\n        // rewrite short names to FQCNs and ensure jars present\n        sig = sig.replace(\"String\", \"java.lang.String\");\n    } else throw ex;\n}","preventionTips":["Use fully-qualified type names in method signature strings.","Keep referenced types on the runtime classpath of the resolving classloader.","Update signature strings after class renames/moves.","Resolve short type names to FQCNs before calling resolveSignature."],"tags":["spring-beans","beanutils","method-resolution","signature","classpath","classloader","type-resolution"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}