spring-projects/spring-framework · error · IllegalArgumentException

Invalid method signature '${signature}': expected opening '(

Error message

Invalid method signature '${signature}': expected opening '(' for args list

What it means

Thrown as IllegalArgumentException by resolveSignature when the supplied signature string contains a ')' but no preceding '(', i.e. a stray closing parenthesis with no opening one (BeanUtils.java:461-464). Like error 156 this is a pure parse failure before method lookup.

Source

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

	 * means the method called {@code methodName} with exactly 0 arguments.
	 * <p>If no method can be found, then {@code null} is returned.
	 * @param signature the method signature as String representation
	 * @param clazz the class to resolve the method signature against
	 * @return the resolved Method
	 * @see #findMethod
	 * @see #findMethodWithMinimalParameters
	 */
	public static @Nullable Method resolveSignature(String signature, Class<?> clazz) {
		Assert.hasText(signature, "'signature' must not be empty");
		Assert.notNull(clazz, "Class must not be null");
		int startParen = signature.indexOf('(');
		int endParen = signature.indexOf(')');
		if (startParen > -1 && endParen == -1) {
			throw new IllegalArgumentException("Invalid method signature '" + signature +
					"': expected closing ')' for args list");
		}
		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);

View on GitHub (pinned to e8729d0438)

Solutions

  1. Correct the signature to use matched parentheses, or remove parentheses to use minimal-arg lookup.
  2. Validate signature shape at load time: indexOf('(') must be < indexOf(')') and both present together, or neither present.
  3. Centralize signature-building in a helper that always emits balanced parentheses.
  4. Add a test fixture covering known-good signatures.

Example fix

// before
resolveSignature("handle)", clazz); // ')' without '('

// after
resolveSignature("handle(String)", clazz);
Defensive patterns

Strategy: validation

Validate before calling

int open = signature.indexOf('('), close = signature.indexOf(')');
if (open == -1 && close > -1) {
  throw new IllegalArgumentException("Malformed signature, missing '(': " + signature);
}

Type guard

public static boolean isBalancedSignature(String s) {
  int o = s.indexOf('('), c = s.indexOf(')');
  return (o == -1 && c == -1) || (o > -1 && c > o);
}

Try / catch

try { BeanUtils.resolveSignature(sig, clazz); }
catch (IllegalArgumentException e) { /* fix the signature string */ }

Prevention

When it happens

Trigger: resolveSignature('foo)', clazz) or 'methodName String)' — a closing paren appears before/without an opening paren.

Common situations: Mis-edited config string, bad concatenation, accidental parenthesis from neighboring tokens, or OCR/import of method names that dropped the '(' .

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/63fc519d31fdc96d.json. Report an issue: GitHub.