spring-projects/spring-framework · error · UnsatisfiedDependencyException

Unsatisfied dependency expressed through field

Error message

Unsatisfied dependency expressed through field

What it means

Thrown as an UnsatisfiedDependencyException when the BeanFactory cannot resolve a value for an @Autowired/@Value field at runtime in an AOT-processed application. The AOT-generated AutowiredFieldValueResolver calls resolveDependency for the field; if that lookup fails (missing bean, ambiguous type, conversion error) the underlying BeansException is wrapped with the InjectionPoint so you can see which field is broken. It is the AOT equivalent of the reflection-based AutowiredAnnotationBeanPostProcessor failure.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/factory/aot/AutowiredFieldValueResolver.java:188

		String beanName = registeredBean.getBeanName();
		Class<?> beanClass = registeredBean.getBeanClass();
		ConfigurableBeanFactory beanFactory = registeredBean.getBeanFactory();
		DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
		descriptor.setContainingClass(beanClass);
		if (this.shortcutBeanName != null) {
			descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcutBeanName);
		}
		Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		try {
			Assert.isInstanceOf(AutowireCapableBeanFactory.class, beanFactory);
			Object value = ((AutowireCapableBeanFactory) beanFactory).resolveDependency(
					descriptor, beanName, autowiredBeanNames, typeConverter);
			registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
			return value;
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
		}
	}

	private Field getField(RegisteredBean registeredBean) {
		Field field = ReflectionUtils.findField(registeredBean.getBeanClass(), this.fieldName);
		Assert.notNull(field, () -> "No field '" + this.fieldName + "' found on " +
				registeredBean.getBeanClass().getName());
		return field;
	}

}

View on GitHub (pinned to 69bf83ad71)

Solutions

  1. Read the InjectionPoint in the stack trace to identify the exact field and its declaring bean, then verify a bean of that type (and qualifier) is registered.
  2. If the dependency is optional, build the resolver with forField(name) instead of forRequiredField(name), or annotate the field with @Autowired(required=false).
  3. Add an explicit bean name via .withShortcut(beanName) or a @Qualifier on the field when multiple candidates of the same type exist.
  4. Ensure placeholder/value resolution is configured (e.g. PropertySourcesPlaceholderConfigurer) and that referenced properties exist in the environment.
  5. Re-run with the JVM (non-AOT) build to reproduce the same UnsatisfiedDependencyException for a friendlier, full-context stack trace.

Example fix

// before: required field with no qualifying bean
@AutowiredFieldValueResolver.forRequiredField("dataSource")
    .resolveAndSet(registeredBean, instance);

// after: optional injection that tolerates absence
AutowiredFieldValueResolver.forField("dataSource")
    .resolveAndSet(registeredBean, instance);
Defensive patterns

Strategy: try-catch

Validate before calling

// Before resolving, confirm the candidate exists and is unique
ConfigurableListableBeanFactory bf = registeredBean.getBeanFactory();
String[] names = bf.getBeanNamesForType(field.getType());
if (names.length == 0 && required) {
    throw new IllegalStateException("No bean of type " + field.getType() + " for field " + field);
}

Try / catch

try {
    resolver.resolveAndSet(registeredBean, instance);
} catch (UnsatisfiedDependencyException ex) {
    InjectionPoint ip = ex.getInjectionPoint();
    // log ip, fall back to a default, or rethrow as a domain-specific error
    throw new ConfigurationException("Cannot wire field " + (ip != null ? ip.getField() : "?"), ex);
}

Prevention

When it happens

Trigger: Calling resolveAndSet(registeredBean, instance) or resolveValue on an AutowiredFieldValueResolver built forField/forRequiredField when beanFactory.resolveDependency(descriptor, ...) throws a BeansException. This happens when the declared field type has no candidate bean, multiple unqualified candidates, or a value that cannot be converted to the field type.

Common situations: Forgetting to register a bean of the field's type in the AOT-optimized context; using @Value('${missing.prop}') without a PropertySourcesPlaceholderConfigurer; a qualifier that no bean satisfies; circular/missing bean after trimming the context for native image; renaming a bean without updating the @Qualifier on the field.

Related errors


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