spring-projects/spring-framework · error · IllegalArgumentException

Specify either 'targetObject' or 'targetBeanName', not both

Error message

Specify either 'targetObject' or 'targetBeanName', not both

What it means

Thrown by PropertyPathFactoryBean.setBeanFactory() when both targetObject (an inline/instance target) and targetBeanName (a named target) have been configured. PropertyPathFactoryBean evaluates a property path on exactly one target; specifying both is ambiguous, so Spring rejects it at the BeanFactory-aware stage.

Solutions

  1. Keep only one: use targetBeanName for a named bean reference, or targetObject for an inline/inner bean.
  2. Prefer targetBeanName with a singleton target so Spring can eagerly resolve and determine the result type.
  3. In code, delete whichever setTargetObject/setTargetBeanName call is unwanted.

Example fix

<!-- before (broken): both set -->
<bean class="...PropertyPathFactoryBean">
  <property name="targetObject" ref="tb"/>
  <property name="targetBeanName" value="tb"/>
  <property name="propertyPath" value="age"/>
</bean>
<!-- after -->
<bean class="...PropertyPathFactoryBean">
  <property name="targetBeanName" value="tb"/>
  <property name="propertyPath" value="age"/>
</bean>
Defensive patterns

Strategy: validation

Validate before calling

if (fb.getTargetObject() != null && /* targetBeanName set */ targetBeanName != null) {
    throw new IllegalStateException("Choose targetObject OR targetBeanName, not both");
}

Type guard

static boolean hasSingleTarget(PropertyPathFactoryBean fb, String targetBeanName) {
    return (fb.getTargetObject() == null) ^ (targetBeanName == null);
}

Try / catch

try {
    fb.setBeanFactory(beanFactory);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("not both")) {
        // drop one of the two targets and retry
    }
    throw ex;
}

Prevention

When it happens

Trigger: XML with both <property name="targetObject" ref="..."> and <property name="targetBeanName" value="..."> on the same PropertyPathFactoryBean. Programmatic calls to setTargetObject(...) and setTargetBeanName(...).

Common situations: Copy-paste from two examples merging both properties. Refactoring from inline bean to bean-name reference and forgetting to remove the old property. Confusion about which form to use.

Related errors


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

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPathFactoryBean.java:164

	/**
	 * The bean name of this PropertyPathFactoryBean will be interpreted
	 * as "beanName.property" pattern, if neither "targetObject" nor
	 * "targetBeanName" nor "propertyPath" have been specified.
	 * This allows for concise bean definitions with just an id/name.
	 */
	@Override
	public void setBeanName(String beanName) {
		this.beanName = StringUtils.trimAllWhitespace(BeanFactoryUtils.originalBeanName(beanName));
	}


	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
		String targetBeanName = this.targetBeanName;

		if (this.targetBeanWrapper != null && targetBeanName != null) {
			throw new IllegalArgumentException("Specify either 'targetObject' or 'targetBeanName', not both");
		}

		if (this.targetBeanWrapper == null && targetBeanName == null) {
			if (this.propertyPath != null) {
				throw new IllegalArgumentException(
						"Specify 'targetObject' or 'targetBeanName' in combination with 'propertyPath'");
			}

			// No other properties specified: check bean name.
			int dotIndex;
			if (this.beanName == null || (dotIndex = this.beanName.indexOf('.')) <= 0) {
				throw new IllegalArgumentException(
						"Neither 'targetObject' nor 'targetBeanName' specified, and PropertyPathFactoryBean " +
						"bean name '" + this.beanName + "' does not follow 'beanName.property' syntax");
			}
			targetBeanName = this.beanName.substring(0, dotIndex);
			this.targetBeanName = targetBeanName;
			this.propertyPath = this.beanName.substring(dotIndex + 1);

View on GitHub (pinned to 69bf83ad71)