spring-projects/spring-framework · error · NotWritablePropertyException

Nested property in path

Error message

Nested property in path '{propertyName}' does not exist

What it means

Thrown by setPropertyValue(String, Object) when navigating a nested property path (e.g. 'a.b.c') raises a NotReadablePropertyException on an intermediate segment. It is rethrown as a NotWritablePropertyException with this message, signalling that a parent property in the write path does not exist (so the leaf cannot be written).

Solutions

  1. Verify each path segment exists (has a readable getter) on the wrapped class; check spelling/case.
  2. Use beanWrapper.isReadableProperty("customer.address") and isWritableProperty("customer.address.city") before setting.
  3. Enable autoGrowNestedPaths (setAutoGrowNestedPaths(true)) if intermediate segments legitimately start null but have typed getters.
  4. If the type was refactored, update the property path / binding source to match the new bean shape.

Example fix

// before
wrapper.setPropertyValue("custmer.address.city", "Berlin"); // typo: custmer

// after
wrapper.setPropertyValue("customer.address.city", "Berlin");
Defensive patterns

Strategy: validation

Validate before calling

String path = "customer.address.city";
BeanWrapper w = new BeanWrapperImpl(bean);
// validate each intermediate segment is readable and the leaf is writable
String[] parts = path.split("\\.");
StringBuilder cur = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
    cur.append(i == 0 ? "" : ".").append(parts[i]);
    if (i < parts.length - 1 && !w.isReadableProperty(cur.toString())) {
        throw new IllegalArgumentException("path segment not readable: " + cur);
    }
}
if (!w.isWritableProperty(path)) {
    throw new IllegalArgumentException("leaf not writable: " + path);
}
w.setPropertyValue(path, value);

Type guard

static boolean pathLooksValid(BeanWrapper w, String path) {
    String[] parts = path.split("\\.");
    StringBuilder cur = new StringBuilder();
    for (int i = 0; i < parts.length; i++) {
        cur.append(i == 0 ? "" : ".").append(parts[i]);
        if (i < parts.length - 1 && !w.isReadableProperty(cur.toString())) return false;
    }
    return w.isWritableProperty(path);
}

Try / catch

try {
    wrapper.setPropertyValue("a.b.c", value);
} catch (NotWritablePropertyException ex) {
    // log and surface a binding error; check segment spelling / bean shape
}

Prevention

When it happens

Trigger: Calling beanWrapper.setPropertyValue("customer.address.city", value) when 'address' (or 'customer') has no getter/field on the target bean, so getPropertyAccessorForPropertyPath fails to resolve the path.

Common situations: Typo in a nested property name in XML/YAML/SpEL binding; renaming a bean property and forgetting to update binding configuration; binding against the wrong bean class; accessing a property that exists on a subtype after the wrapper was created on the supertype.

Related errors


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

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java:222

		return this.rootObject;
	}

	/**
	 * Return the class of the root object at the top of the path of this accessor.
	 * @see #getNestedPath
	 */
	public final Class<?> getRootClass() {
		return getRootInstance().getClass();
	}

	@Override
	public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
		AbstractNestablePropertyAccessor nestedPa;
		try {
			nestedPa = getPropertyAccessorForPropertyPath(propertyName);
		}
		catch (NotReadablePropertyException ex) {
			throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
					"Nested property in path '" + propertyName + "' does not exist", ex);
		}
		PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
		nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
	}

	@Override
	public void setPropertyValue(PropertyValue pv) throws BeansException {
		PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
		if (tokens == null) {
			String propertyName = pv.getName();
			AbstractNestablePropertyAccessor nestedPa;
			try {
				nestedPa = getPropertyAccessorForPropertyPath(propertyName);
			}
			catch (NotReadablePropertyException ex) {
				throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
						"Nested property in path '" + propertyName + "' does not exist", ex);

View on GitHub (pinned to 69bf83ad71)