spring-projects/spring-framework · error · InvalidPropertyException

No property handler found

Error message

No property handler found

What it means

Thrown in processKeyedProperty when writing an indexed/mapped property such as 'items[0]' or 'map[key]'. The code resolves the enclosing value fine, then asks getLocalPropertyHandler(tokens.actualName) for the named property; if no handler exists (the bean has no getter/setter for that name) an InvalidPropertyException with 'No property handler found' is raised. It indicates the indexed/mapped accessor was applied to a name the bean does not expose.

Source

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

			setPropertyValue(tokens, pv);
		}
	}

	protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
		if (tokens.keys != null) {
			processKeyedProperty(tokens, pv);
		}
		else {
			processLocalProperty(tokens, pv);
		}
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void processKeyedProperty(PropertyTokenHolder tokens, PropertyValue pv) {
		Object propValue = getPropertyHoldingValue(tokens);
		PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
		if (ph == null) {
			throw new InvalidPropertyException(
					getRootClass(), this.nestedPath + tokens.actualName, "No property handler found");
		}
		Assert.state(tokens.keys != null, "No token keys");
		String lastKey = tokens.keys[tokens.keys.length - 1];

		if (propValue.getClass().isArray()) {
			Class<?> componentType = propValue.getClass().componentType();
			int arrayIndex = Integer.parseInt(lastKey);
			Object oldValue = null;
			try {
				if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
					oldValue = Array.get(propValue, arrayIndex);
				}
				Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
						componentType, ph.nested(tokens.keys.length));
				int length = Array.getLength(propValue);
				if (arrayIndex >= length && arrayIndex < getAutoGrowCollectionLimit()) {
					Object newArray = Array.newInstance(componentType, arrayIndex + 1);

View on GitHub (pinned to e8729d0438)

Solutions

  1. Verify the bean exposes a getter/setter for the base property named before the index (tokens.actualName).
  2. Correct the spelling of the collection/map field in the property path.
  3. If binding untrusted/loose data, mark unknown fields to be ignored at the binder level.

Example fix

// before
public class Order { private List<Item> lines; public List<Item> getLines() { return lines; } public void setLines(List<Item> l) { this.lines = l; } }
wrapper.setPropertyValue("items[0]", newItem); // wrong name

// after
wrapper.setPropertyValue("lines[0]", newItem);
Defensive patterns

Strategy: validation

Validate before calling

String base = path.replaceAll("\\[.*$", "");
if (wrapper.getPropertyHandler(base) != null) {
    wrapper.setPropertyValue(path, value);
}

Type guard

static boolean hasIndexedBase(BeanWrapper bw, String path) {
    String base = path.replaceAll("\\[.*$", "");
    return bw.isReadableProperty(base) || bw.isWritableProperty(base);
}

Try / catch

try { wrapper.setPropertyValue(path, value); }
catch (InvalidPropertyException ex) { /* log path, skip */ }

Prevention

When it happens

Trigger: wrapper.setPropertyValue("items[0]", x) on a bean with no getItems/setItems; binding into 'records[3].name' where 'records' is not a recognized property of the bean; a SpEL/BeanWrapper path with a misspelled collection field followed by an index.

Common situations: Form binding onto a DTO where the collection field was renamed; mapping external data into a bean via BeanWrapper with an incorrect field name; refactoring that dropped a getter/setter but left binding paths referencing it.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/d49c579e65673efc.json. Report an issue: GitHub.