spring-projects/spring-framework · error · UnsatisfiedDependencyException
Unsatisfied dependency expressed through parameter
Error message
Unsatisfied dependency expressed through parameter
What it means
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.
Source
Thrown at spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredMethodArgumentsResolver.java:185
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < argumentCount; i++) {
MethodParameter parameter = new MethodParameter(method, i);
DependencyDescriptor descriptor = new DependencyDescriptor(parameter, this.required);
descriptor.setContainingClass(beanClass);
String shortcut = (this.shortcutBeanNames != null ? this.shortcutBeanNames[i] : null);
if (shortcut != null) {
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
}
try {
Object argument = autowireCapableBeanFactory.resolveDependency(
descriptor, beanName, autowiredBeanNames, typeConverter);
if (argument == null && !this.required) {
return null;
}
arguments[i] = argument;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
}
}
registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
return AutowiredArguments.of(arguments);
}
private Method getMethod(RegisteredBean registeredBean) {
Method method = ReflectionUtils.findMethod(registeredBean.getBeanClass(),
this.methodName, this.parameterTypes);
Assert.notNull(method, () ->
"Method '%s' with parameter types [%s] declared on %s could not be found.".formatted(
this.methodName, toCommaSeparatedNames(this.parameterTypes),
registeredBean.getBeanClass().getName()));
return method;
}
private String toCommaSeparatedNames(Class<?>... parameterTypes) {
return Arrays.stream(parameterTypes).map(Class::getName)View on GitHub (pinned to 69bf83ad71)
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.
Example fix
// before: required method injection failing on missing collaborator
resolver.resolveAndSet(registeredBean, instance); // throws on param 0
// after: pin the ambiguous argument to a named bean
resolver.withShortcut("redisTemplate").resolveAndSet(registeredBean, instance); Defensive patterns
Strategy: try-catch
Validate before calling
// Verify each method-parameter type is resolvable before resolving
ConfigurableListableBeanFactory bf = registeredBean.getBeanFactory();
for (Class<?> pt : method.getParameterTypes()) {
String[] names = bf.getBeanNamesForType(pt);
if (names.length == 0 && required) {
throw new IllegalStateException("No bean of type " + pt + " for " + method);
}
} Try / catch
try {
resolver.resolveAndSet(registeredBean, instance);
} catch (UnsatisfiedDependencyException ex) {
InjectionPoint ip = ex.getInjectionPoint();
MethodParameter mp = (ip != null) ? ip.getMethodParameter() : null;
throw new ConfigurationException("Cannot wire method param " + mp, ex);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unsatisfied dependency expressed through field
- Unsatisfied dependency expressed through injection point
- No unique bean definition
- Invalid autowire-marked constructors: {}. Found constructor
- Injection of autowired dependencies failed
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/0f0d3fdf82d4c2ed.
Report an issue: GitHub.