spring-projects/spring-framework · error · IllegalArgumentException

Invalid method signature: unable to resolve type

Error message

Invalid method signature: unable to resolve type [{parameterTypeName}] for argument {i}. Root cause: {ex}

What it means

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.

Solutions

  1. Use the fully-qualified type name, e.g. "doStuff(java.lang.String, java.lang.Integer)".
  2. Ensure the referenced type's JAR/class is on the runtime classpath of the resolving classloader.
  3. After a rename/refactor, update all string-based method signatures.
  4. If short names are desired, resolve them to FQCNs yourself before calling resolveSignature.

Example fix

// before
Method m = BeanUtils.resolveSignature("doStuff(String, Integer)", clazz);

// after
Method m = BeanUtils.resolveSignature("doStuff(java.lang.String, java.lang.Integer)", clazz);
Defensive patterns

Strategy: validation

Validate before calling

// Validate each type name resolves on the target classloader first
String sig = "doStuff(java.lang.String, java.lang.Integer)";
for (String t : sig.substring(sig.indexOf('(')+1, sig.indexOf(')')).split(",")) {
    ClassUtils.forName(t.trim(), clazz.getClassLoader());
}
BeanUtils.resolveSignature(sig, clazz);

Type guard

static boolean allTypesResolvable(String sig, ClassLoader cl) {
    String args = sig.substring(sig.indexOf('(')+1, sig.indexOf(')'));
    for (String t : args.split(",")) {
        if (t.isBlank()) continue;
        try { ClassUtils.forName(t.trim(), cl); }
        catch (Throwable e) { return false; }
    }
    return true;
}

Try / catch

try {
    BeanUtils.resolveSignature(sig, clazz);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("unable to resolve type")) {
        // rewrite short names to FQCNs and ensure jars present
        sig = sig.replace("String", "java.lang.String");
    } else throw ex;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/d7299c0afc578757. Report an issue: GitHub.

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/BeanUtils.java:479

		else if (startParen == -1 && endParen > -1) {
			throw new IllegalArgumentException("Invalid method signature '" + signature +
					"': expected opening '(' for args list");
		}
		else if (startParen == -1) {
			return findMethodWithMinimalParameters(clazz, signature);
		}
		else {
			String methodName = signature.substring(0, startParen);
			String[] parameterTypeNames =
					StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen));
			Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
			for (int i = 0; i < parameterTypeNames.length; i++) {
				String parameterTypeName = parameterTypeNames[i].trim();
				try {
					parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());
				}
				catch (Throwable ex) {
					throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +
							parameterTypeName + "] for argument " + i + ". Root cause: " + ex);
				}
			}
			return findMethod(clazz, methodName, parameterTypes);
		}
	}


	/**
	 * Retrieve the JavaBeans {@code PropertyDescriptor}s of a given class.
	 * @param clazz the Class to retrieve the PropertyDescriptors for
	 * @return an array of {@code PropertyDescriptors} for the given class
	 * @throws BeansException if PropertyDescriptor look fails
	 */
	public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {
		return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors();
	}

View on GitHub (pinned to 69bf83ad71)