spring-projects/spring-framework · error · InvalidPropertyException
No property handler found
Error message
No property handler found
What it means
Thrown by processKeyedProperty when getLocalPropertyHandler(tokens.actualName) returns null for a property that is being addressed with a key/index (e.g. 'items[0]'). A keyed write needs a PropertyHandler to resolve element/key types and the setter; if no handler exists for the base property the framework cannot perform the indexed operation.
Solutions
- Confirm the base property (e.g. 'items') has a getter (and setter for writes) on the wrapped bean.
- Switch the accessor to direct field access (BeanWrapper / DirectFieldAccessor) if the value is a field with no accessor methods.
- If binding into a Map held by the bean, target the property name then the key: 'myMap[key]' where 'myMap' is a real property.
- Correct the property name spelling/case to match the bean.
Example fix
// before
wrapper.setPropertyValue("itemz[0]", x); // property is 'items', not 'itemz' -> No property handler found
// after
wrapper.setPropertyValue("items[0]", x); Defensive patterns
Strategy: validation
Validate before calling
BeanWrapper w = new BeanWrapperImpl(bean);
String base = tokensBeforeIndex; // e.g. "items"
if (w.getPropertyType(base) == null) {
throw new IllegalArgumentException("no property handler for " + base);
}
w.setPropertyValue(base + "[0]", value); Type guard
static boolean hasPropertyHandler(BeanWrapper w, String base) {
try { return w.getPropertyDescriptor(base) != null; }
catch (InvalidPropertyException e) { return false; }
} Try / catch
try {
wrapper.setPropertyValue("items[0]", value);
} catch (InvalidPropertyException ex) {
if (ex.getMessage().contains("No property handler")) { /* expose field-access or fix name */ }
else throw ex;
} Prevention
- Confirm collection/map properties have getters (and setters) — BeanWrapper honors accessors, not raw fields.
- Switch to DirectFieldAccessor if you intentionally bind to public fields.
- Add a property-descriptor check before indexed writes from user input.
When it happens
Trigger: Calling setPropertyValue("items[0]", value) on a BeanWrapper where 'items' is not a recognized JavaBean property (no getter/setter and no field exposure) of the wrapped object.
Common situations: Binding to a public field directly with indexed syntax on a BeanWrapper that only honors getters/setters; misspelled collection property; wrapping a Map itself and using indexed syntax expecting map semantics on a non-property; using DirectFieldAccess that wasn't enabled so a field isn't seen as a property.
Related errors
- Cannot access indexed value in property referenced in…
- Cannot access indexed value in property referenced in…
- Cannot access indexed value of property referenced in…
- Property referenced in indexed property path
- Property referenced in indexed property path
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/d49c579e65673efc.
Report an issue: GitHub.
Appendix: 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 69bf83ad71)