spring-projects/spring-framework · error · NotWritablePropertyException

Invalid property '{propertyName}' of bean class [{beanClass.

Error message

Invalid property '{propertyName}' of bean class [{beanClass.getName()}]: {matches.buildErrorMessage()}

What it means

Thrown as NotWritablePropertyException by BeanWrapperImpl.createNotWritablePropertyException when a property name cannot be resolved to a writable property (no matching PropertyDescriptor with a write method). The message includes PropertyMatches.buildErrorMessage() which suggests similar property names, so the exception text usually shows 'Did you mean?' candidates.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java:205

		TypeDescriptor td = ((GenericTypeAwarePropertyDescriptor) pd).getTypeDescriptor();
		return convertForProperty(propertyName, null, value, td);
	}

	@Override
	protected @Nullable PropertyHandler getLocalPropertyHandler(String propertyName) {
		PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
		return (pd != null ? new BeanPropertyHandler((GenericTypeAwarePropertyDescriptor) pd) : null);
	}

	@Override
	protected BeanWrapperImpl newNestedPropertyAccessor(Object object, String nestedPath) {
		return new BeanWrapperImpl(object, nestedPath, this);
	}

	@Override
	protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
		PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass());
		throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
				matches.buildErrorMessage(), matches.getPossibleMatches());
	}

	@Override
	public PropertyDescriptor[] getPropertyDescriptors() {
		return getCachedIntrospectionResults().getPropertyDescriptors();
	}

	@Override
	public PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException {
		BeanWrapperImpl nestedBw = (BeanWrapperImpl) getPropertyAccessorForPropertyPath(propertyName);
		String finalPath = getFinalPath(nestedBw, propertyName);
		PropertyDescriptor pd = nestedBw.getCachedIntrospectionResults().getPropertyDescriptor(finalPath);
		if (pd == null) {
			throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
					"No property '" + propertyName + "' found");
		}
		return pd;

View on GitHub (pinned to 69bf83ad71)

Solutions

  1. Use the suggested 'possible matches' from the exception message to correct the property name.
  2. Add a public setter for the property on the target class (or open it for field access if using a field-accessor).
  3. Allow unknown fields if expected: configure the DataBinder with setIgnoreUnknownFields(true) (Spring Boot @ConfigurationProperties) or skip the binding path.

Example fix

// before
wrapper.setPropertyValue("fristName", "Jane"); // typo

// after
wrapper.setPropertyValue("firstName", "Jane");
Defensive patterns

Strategy: validation

Validate before calling

// before binding
Set<String> writable = Arrays.stream(wrapper.getPropertyDescriptors())
    .filter(pd -> pd.getWriteMethod() != null)
    .map(PropertyDescriptor::getName).collect(Collectors.toSet());
if (!writable.contains(name)) {
    throw new IllegalArgumentException("not writable: " + name);
}

Type guard

static boolean isWritable(BeanWrapper w, String name) {
    try { return w.getPropertyDescriptor(name).getWriteMethod() != null; }
    catch (InvalidPropertyException | NotWritablePropertyException e) { return false; }
}

Prevention

When it happens

Trigger: Calling setPropertyValue / setPropertyValues on a BeanWrapperImpl with a property name that does not correspond to a writable bean property of the root class. Triggered from the base AbstractNestablePropertyAccessor when getLocalPropertyHandler returns null and a write is attempted.

Common situations: Typo in a property name in @Value SpEL, DataBinder/ServletRequestDataBinder binding a request parameter that has no setter, @ConfigurationProperties prefix mismatch, or a setter that was removed/renamed.

Related errors


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