spring-projects/spring-framework · error · IllegalArgumentException

Cannot resolve method '{methodName}' to a unique method. Att

Error message

Cannot resolve method '{methodName}' to a unique method. Attempted to resolve to overloaded method with the least number of parameters but there were {numMethodsFoundWithCurrentMinimumArgs} candidates.

What it means

Thrown as IllegalArgumentException by findMethodWithMinimalParameters at BeanUtils.java:426 when several methods share the requested name AND tie for the least number of parameters (numMethodsFoundWithCurrentMinimumArgs > 1). Used by findMethodWithMinimalParameters/findMethodWithMinimalParameters overloads and indirectly by resolveSignature when no arg list is given. It reports how many ambiguous candidates were found.

Source

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

				int numParams = method.getParameterCount();
				if (targetMethod == null || numParams < targetMethod.getParameterCount()) {
					targetMethod = method;
					numMethodsFoundWithCurrentMinimumArgs = 1;
				}
				else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
					if (targetMethod.isBridge()) {
						// Prefer regular method over bridge...
						targetMethod = method;
					}
					else {
						// Additional candidate with same length
						numMethodsFoundWithCurrentMinimumArgs++;
					}
				}
			}
		}
		if (numMethodsFoundWithCurrentMinimumArgs > 1) {
			throw new IllegalArgumentException("Cannot resolve method '" + methodName +
					"' to a unique method. Attempted to resolve to overloaded method with " +
					"the least number of parameters but there were " +
					numMethodsFoundWithCurrentMinimumArgs + " candidates.");
		}
		return targetMethod;
	}

	/**
	 * Parse a method signature in the form {@code methodName[([arg_list])]},
	 * where {@code arg_list} is an optional, comma-separated list of fully-qualified
	 * type names, and attempts to resolve that signature against the supplied {@code Class}.
	 * <p>When not supplying an argument list ({@code methodName}) the method whose name
	 * matches and has the least number of parameters will be returned. When supplying an
	 * argument type list, only the method whose name and argument types match will be returned.
	 * <p>Note then that {@code methodName} and {@code methodName()} are <strong>not</strong>
	 * resolved in the same way. The signature {@code methodName} means the method called
	 * {@code methodName} with the least number of arguments, whereas {@code methodName()}
	 * means the method called {@code methodName} with exactly 0 arguments.

View on GitHub (pinned to 69bf83ad71)

Solutions

  1. Use the fully-qualified signature form: resolveSignature("save(java.lang.String)", clazz) or findMethod(clazz, "save", String.class) to disambiguate by parameter types.
  2. Rename or remove one of the overloaded methods so the name is unique at the minimal param count.
  3. If the overloads are genuinely needed, pass explicit Class[] param types to findMethod.

Example fix

// before
Method m = BeanUtils.findMethodWithMinimalParameters(Svc.class, "save"); // save(String) & save(int)

// after
Method m = BeanUtils.findMethod(Svc.class, "save", String.class);
Defensive patterns

Strategy: validation

Validate before calling

// Disambiguate by name AND param types instead of name only
Method m = BeanUtils.findMethod(clazz, "save", String.class);

Type guard

static boolean uniquelyNamedMinimal(Class<?> c, String name) {
    int min = Integer.MAX_VALUE, count = 0;
    for (Method md : c.getMethods()) {
        if (md.getName().equals(name)) {
            if (md.getParameterCount() < min) { min = md.getParameterCount(); count = 1; }
            else if (md.getParameterCount() == min) count++;
        }
    }
    return count <= 1;
}

Try / catch

try {
    Method m = BeanUtils.findMethodWithMinimalParameters(clazz, "save");
} catch (IllegalArgumentException ex) {
    // overloaded & ambiguous -> resolve with explicit param types
    Method m = BeanUtils.findMethod(clazz, "save", String.class);
}

Prevention

When it happens

Trigger: Calling findMethodWithMinimalParameters(clazz, "save") when 'save' has e.g. save(String) and save(int) — both have one parameter so neither is uniquely minimal. Bridge methods are de-prioritized but two real methods with the same param count still collide.

Common situations: Resolving an overloaded method by name only (no arg types) in SpEL/attribute/method-name config; @Scheduled/@Cacheable method-name lookups on overloaded methods; method-invocation factory beans; XML method-injection referencing only a name.

Related errors


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