{"record":{"id":"a7db40a70fed455b","repo":"spring-projects/spring-framework","slug":"cannot-resolve-method-methodname-to-a-unique-m","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/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java#L408-L444","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the fully-qualified signature form: resolveSignature(\"save(java.lang.String)\", clazz) or findMethod(clazz, \"save\", String.class) to disambiguate by parameter types.","Rename or remove one of the overloaded methods so the name is unique at the minimal param count.","If the overloads are genuinely needed, pass explicit Class[] param types to findMethod."],"exampleFix":"// before\nMethod m = BeanUtils.findMethodWithMinimalParameters(Svc.class, \"save\"); // save(String) & save(int)\n\n// after\nMethod m = BeanUtils.findMethod(Svc.class, \"save\", String.class);","handlingStrategy":"validation","validationCode":"// Disambiguate by name AND param types instead of name only\nMethod m = BeanUtils.findMethod(clazz, \"save\", String.class);","typeGuard":"static boolean uniquelyNamedMinimal(Class<?> c, String name) {\n    int min = Integer.MAX_VALUE, count = 0;\n    for (Method md : c.getMethods()) {\n        if (md.getName().equals(name)) {\n            if (md.getParameterCount() < min) { min = md.getParameterCount(); count = 1; }\n            else if (md.getParameterCount() == min) count++;\n        }\n    }\n    return count <= 1;\n}","tryCatchPattern":"try {\n    Method m = BeanUtils.findMethodWithMinimalParameters(clazz, \"save\");\n} catch (IllegalArgumentException ex) {\n    // overloaded & ambiguous -> resolve with explicit param types\n    Method m = BeanUtils.findMethod(clazz, \"save\", String.class);\n}","preventionTips":["Prefer findMethod(clazz, name, paramTypes) or resolveSignature(\"name(types)\") over name-only lookup.","Avoid name-only resolution on classes with overloaded methods.","Rename one of the overloaded methods if name-only lookup is required by config.","When generating config, always include the parameter type list."],"tags":["spring-beans","beanutils","method-resolution","overloading","reflection","ambiguity"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}