spring-projects/spring-framework · error · IntrospectionException
Type mismatch between indexed and non-indexed methods
Error message
Type mismatch between indexed and non-indexed methods: {} - {} What it means
Thrown when a property exposes both a non-indexed accessor (getX()/setX()) and indexed accessors (getX(int)/setX(int, T)), but the non-indexed property type is not an array whose component type equals the indexed element type. Raised at line 239: propertyType must be an array and propertyType.componentType() must equal indexedPropertyType, otherwise IntrospectionException.
Solutions
- Align the non-indexed accessor to return an array whose component type matches the indexed element type (e.g. String[] getItems() with String getItem(int)).
- Or remove the non-indexed getter/setter so the property is treated as indexed-only.
- Or remove the indexed accessors if the collection-style getter is the intended public API.
Example fix
// before
private List<String> items;
public List<String> getItems() { return items; }
public String getItem(int i) { return items.get(i); }
// after
private String[] items;
public String[] getItems() { return items; }
public String getItem(int i) { return items[i]; } Defensive patterns
Strategy: validation
Validate before calling
// Ensure non-indexed type is array with matching component when indexed accessors exist
Class<?> pt = nonIndexedRead.getReturnType();
Class<?> it = indexedRead.getReturnType();
if (pt != null && (!pt.isArray() || pt.componentType() != it)) {
throw new IllegalStateException("non-indexed type must be " + it + "[]");
} Type guard
static boolean indexedMatchesNonIndexed(Class<?> nonIndexedType, Class<?> indexedType) {
return nonIndexedType == null || (nonIndexedType.isArray() && nonIndexedType.componentType() == indexedType);
} Prevention
- When a bean has both getX() and getX(int), make getX() return T[].
- If you switched to List<T>, drop the indexed getX(int)/setX(int, T) methods.
- Test introspection in a unit test so mismatches surface before Spring binds.
When it happens
Trigger: A bean has List<String> getItems() as the non-indexed getter plus String getItem(int) — List is not an array, so the isArray() check fails. Or String[] getItems() with Integer getItem(int) — component type mismatch.
Common situations: Wrapping an internal List but also providing positional indexed accessors; refactoring from arrays to List collections while leaving the indexed methods in place; code-generated beans mixing collection and array styles.
Related errors
- Type mismatch between indexed read and write methods
- Non int index to indexed write method
- Bad indexed read method arg count
- Bad indexed write method arg count
- Indexed read method returns void
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/ec13175ee8889aa6.
Report an issue: GitHub.
Appendix: source
Thrown at spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java:239
// Write method's property type potentially more specific
indexedPropertyType = params[1];
}
else if (params[1].isAssignableFrom(indexedPropertyType)) {
// Proceed with read method's property type
}
else {
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
indexedReadMethod + " - " + indexedWriteMethod);
}
}
else {
indexedPropertyType = params[1];
}
}
if (propertyType != null && (!propertyType.isArray() ||
propertyType.componentType() != indexedPropertyType)) {
throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
indexedReadMethod + " - " + indexedWriteMethod);
}
return indexedPropertyType;
}
/**
* Compare the given {@code PropertyDescriptors} and return {@code true} if
* they are equivalent, i.e. their read method, write method, property type,
* property editor and flags are equivalent.
* @see java.beans.PropertyDescriptor#equals(Object)
*/
public static boolean equals(PropertyDescriptor pd, PropertyDescriptor otherPd) {
return (ObjectUtils.nullSafeEquals(pd.getReadMethod(), otherPd.getReadMethod()) &&
ObjectUtils.nullSafeEquals(pd.getWriteMethod(), otherPd.getWriteMethod()) &&
ObjectUtils.nullSafeEquals(pd.getPropertyType(), otherPd.getPropertyType()) &&
ObjectUtils.nullSafeEquals(pd.getPropertyEditorClass(), otherPd.getPropertyEditorClass()) &&
pd.isBound() == otherPd.isBound() && pd.isConstrained() == otherPd.isConstrained());View on GitHub (pinned to 69bf83ad71)