{"record":{"id":"0f0d3fdf82d4c2ed","repo":"spring-projects/spring-framework","slug":"unsatisfied-dependency-expressed-through-parameter","errorCode":null,"errorMessage":"Unsatisfied dependency expressed through parameter","messagePattern":"Unsatisfied dependency expressed through parameter","errorType":"exception","errorClass":"UnsatisfiedDependencyException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java","lineNumber":185,"sourceCode":"\t\tTypeConverter typeConverter = beanFactory.getTypeConverter();\n\t\tfor (int i = 0; i < argumentCount; i++) {\n\t\t\tMethodParameter parameter = new MethodParameter(method, i);\n\t\t\tDependencyDescriptor descriptor = new DependencyDescriptor(parameter, this.required);\n\t\t\tdescriptor.setContainingClass(beanClass);\n\t\t\tString shortcut = (this.shortcutBeanNames != null ? this.shortcutBeanNames[i] : null);\n\t\t\tif (shortcut != null) {\n\t\t\t\tdescriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tObject argument = autowireCapableBeanFactory.resolveDependency(\n\t\t\t\t\t\tdescriptor, beanName, autowiredBeanNames, typeConverter);\n\t\t\t\tif (argument == null && !this.required) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\targuments[i] = argument;\n\t\t\t}\n\t\t\tcatch (BeansException ex) {\n\t\t\t\tthrow new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);\n\t\t\t}\n\t\t}\n\t\tregisterDependentBeans(beanFactory, beanName, autowiredBeanNames);\n\t\treturn AutowiredArguments.of(arguments);\n\t}\n\n\tprivate Method getMethod(RegisteredBean registeredBean) {\n\t\tMethod method = ReflectionUtils.findMethod(registeredBean.getBeanClass(),\n\t\t\t\tthis.methodName, this.parameterTypes);\n\t\tAssert.notNull(method, () ->\n\t\t\t\t\"Method '%s' with parameter types [%s] declared on %s could not be found.\".formatted(\n\t\t\t\t\t\tthis.methodName, toCommaSeparatedNames(this.parameterTypes),\n\t\t\t\t\t\tregisteredBean.getBeanClass().getName()));\n\t\treturn method;\n\t}\n\n\tprivate String toCommaSeparatedNames(Class<?>... parameterTypes) {\n\t\treturn Arrays.stream(parameterTypes).map(Class::getName)","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java#L167-L203","documentation":"Thrown as an UnsatisfiedDependencyException when an @Autowired method (e.g. a setter or arbitrary method) cannot have one of its arguments resolved by the BeanFactory in an AOT-processed application. AutowiredMethodArgumentsResolver iterates the method's parameters, builds a DependencyDescriptor for each, and calls resolveDependency; any BeansException is wrapped with an InjectionPoint(MethodParameter) indicating the offending parameter. It is the AOT counterpart of method injection failures.","triggerScenarios":"Calling resolveAndSet/resolveArguments on an AutowiredMethodArgumentsResolver where at least one MethodParameter's resolveDependency call throws. Triggers when a required parameter type is missing, ambiguous without a qualifier, or unconvertible; argument resolution is skipped (returns null) only if the resolver was built for non-required injection.","commonSituations":"Setter/method injection where a collaborator bean was removed from the native-image subset; @Autowired on a method whose parameter uses a generic collection type not exposed as a bean; mismatched qualifier on a method parameter; bean renamed or its primary status dropped so multiple candidates now collide.","solutions":["Inspect the InjectionPoint in the exception to find the failing method and parameter index, then ensure exactly one qualifying bean is available.","If the parameter is optional, build the resolver without 'required' semantics so a null argument short-circuits the method call instead of failing.","Add @Qualifier to the parameter or use withShortcut(beanNames) to pin each argument to a specific bean name.","Register the missing bean, or expose it as @Primary if multiple candidates exist and one should win.","Confirm type conversion is possible for @Value parameters and that placeholders resolve in the environment."],"exampleFix":"// before: required method injection failing on missing collaborator\nresolver.resolveAndSet(registeredBean, instance); // throws on param 0\n\n// after: pin the ambiguous argument to a named bean\nresolver.withShortcut(\"redisTemplate\").resolveAndSet(registeredBean, instance);","handlingStrategy":"try-catch","validationCode":"// Verify each method-parameter type is resolvable before resolving\nConfigurableListableBeanFactory bf = registeredBean.getBeanFactory();\nfor (Class<?> pt : method.getParameterTypes()) {\n    String[] names = bf.getBeanNamesForType(pt);\n    if (names.length == 0 && required) {\n        throw new IllegalStateException(\"No bean of type \" + pt + \" for \" + method);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    resolver.resolveAndSet(registeredBean, instance);\n} catch (UnsatisfiedDependencyException ex) {\n    InjectionPoint ip = ex.getInjectionPoint();\n    MethodParameter mp = (ip != null) ? ip.getMethodParameter() : null;\n    throw new ConfigurationException(\"Cannot wire method param \" + mp, ex);\n}","preventionTips":["Annotate method parameters with @Qualifier when more than one candidate type exists.","Mark optional parameters and build the resolver as non-required so absence does not fail resolution.","Add a context-load smoke test in CI to catch unsatisfied method injections early.","Avoid @Autowired on methods with many parameters; prefer constructor injection."],"tags":["spring","aot","dependency-injection","autowiring","method-injection"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}