{"id":"01c80a1507cd4972","repo":"spring-projects/spring-framework","slug":"cannot-resolve-method-methodname-to-a-unique","errorCode":null,"errorMessage":"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.","messagePattern":"Cannot resolve method '(.+?)' to a unique method\\. Attempted to resolve to overloaded method with the least number of parameters but there were (.+?) candidates\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/BeanUtils.java","lineNumber":426,"sourceCode":"\t\t\t\tint numParams = method.getParameterCount();\n\t\t\t\tif (targetMethod == null || numParams < targetMethod.getParameterCount()) {\n\t\t\t\t\ttargetMethod = method;\n\t\t\t\t\tnumMethodsFoundWithCurrentMinimumArgs = 1;\n\t\t\t\t}\n\t\t\t\telse if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {\n\t\t\t\t\tif (targetMethod.isBridge()) {\n\t\t\t\t\t\t// Prefer regular method over bridge...\n\t\t\t\t\t\ttargetMethod = method;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Additional candidate with same length\n\t\t\t\t\t\tnumMethodsFoundWithCurrentMinimumArgs++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (numMethodsFoundWithCurrentMinimumArgs > 1) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot resolve method '\" + methodName +\n\t\t\t\t\t\"' to a unique method. Attempted to resolve to overloaded method with \" +\n\t\t\t\t\t\"the least number of parameters but there were \" +\n\t\t\t\t\tnumMethodsFoundWithCurrentMinimumArgs + \" candidates.\");\n\t\t}\n\t\treturn targetMethod;\n\t}\n\n\t/**\n\t * Parse a method signature in the form {@code methodName[([arg_list])]},\n\t * where {@code arg_list} is an optional, comma-separated list of fully-qualified\n\t * type names, and attempts to resolve that signature against the supplied {@code Class}.\n\t * <p>When not supplying an argument list ({@code methodName}) the method whose name\n\t * matches and has the least number of parameters will be returned. When supplying an\n\t * argument type list, only the method whose name and argument types match will be returned.\n\t * <p>Note then that {@code methodName} and {@code methodName()} are <strong>not</strong>\n\t * resolved in the same way. The signature {@code methodName} means the method called\n\t * {@code methodName} with the least number of arguments, whereas {@code methodName()}\n\t * means the method called {@code methodName} with exactly 0 arguments.","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java#L408-L444","documentation":"Thrown as IllegalArgumentException by findMethodWithMinimalParameters / resolveSignature when more than one method with the given name share the smallest parameter count, so the 'least parameters' heuristic cannot pick a unique winner (BeanUtils.java:425-430). The count of ambiguous candidates is included in the message.","triggerScenarios":"resolveSignature('methodName', clazz) with no argument list, or findMethodWithMinimalParameters(clazz, 'methodName'), where the class declares two or more overloads with the same minimal arity (e.g. foo() and foo() from different interfaces, or foo(int) and foo(String)).","commonSituations":"Method-resolver utilities, scheduler/transaction attribute parsing, pointcut expressions, and AOP config that take a bare method name. Class hierarchies introducing same-arity overloads. Bridge methods (note the code excludes isBridge from counting, but real overloads still collide).","solutions":["Provide the full signature with argument types in resolveSignature: 'methodName(int, java.lang.String)' to disambiguate.","Rename one of the colliding overloads if you control the class.","Use findMethod(clazz, name, paramTypes...) directly with explicit parameter types instead of the minimal-args heuristic.","Reduce accidental same-arity overloads (e.g. consolidate or remove one)."],"exampleFix":"// before\nresolveSignature(\"persist\", repo.getClass()); // persist(int) & persist(String) ambiguous\n\n// after\nresolveSignature(\"persist(int)\", repo.getClass());","handlingStrategy":"validation","validationCode":"// Detect same-arity overload collision before resolving\nlong minArity = Arrays.stream(clazz.getMethods())\n    .filter(m -> m.getName().equals(methodName) && !m.isBridge())\n    .mapToInt(Method::getParameterCount).min().orElse(-1);\nlong count = Arrays.stream(clazz.getMethods())\n    .filter(m -> m.getName().equals(methodName) && !m.isBridge()\n        && m.getParameterCount() == minArity).count();\nif (count > 1) { /* supply full signature instead */ }","typeGuard":"public static boolean methodResolvableByName(Class<?> c, String name) {\n  try { BeanUtils.findMethodWithMinimalParameters(c, name); return true; }\n  catch (IllegalArgumentException e) { return false; }\n}","tryCatchPattern":"try { BeanUtils.resolveSignature(name, clazz); }\ncatch (IllegalArgumentException e) {\n  BeanUtils.resolveSignature(name + \"(int)\", clazz); // disambiguate with arg types\n}","preventionTips":["Provide the full signature 'name(argType, ...)' when overloads exist.","Avoid same-arity overloads where possible.","Use findMethod(clazz, name, paramTypes) with explicit types."],"tags":["spring-beans","beanutils","method-resolution","overloading","ambiguous"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}