spring-projects/spring-framework · error · InvalidPropertyException
Invalid array index in property path
Error message
Invalid array index in property path '{tokens.canonicalName}' What it means
Thrown by processKeyedProperty in the array branch when Array.set throws IndexOutOfBoundsException. Spring will auto-grow the array up to getAutoGrowCollectionLimit() (default 256); beyond that, or when autoGrow is disabled, the out-of-bounds is wrapped as InvalidPropertyException.
Solutions
- Pre-size / pre-allocate the target array so the index is in range.
- Enable autoGrowNestedPaths and raise setAutoGrowCollectionLimit if the index is legitimate (mind memory).
- Validate the incoming index on the controller/binder side and reject values beyond the array bounds.
- Switch from an array to a List/Map if indices are sparse or arbitrary.
Example fix
// before
wrapper.setAutoGrowNestedPaths(false);
wrapper.setPropertyValue("arr[5]", v); // arr.length == 0
// after
wrapper.setAutoGrowNestedPaths(true);
wrapper.setAutoGrowCollectionLimit(64);
wrapper.setPropertyValue("arr[5]", v); Defensive patterns
Strategy: validation
Validate before calling
BeanWrapper w = new BeanWrapperImpl(bean);
String base = "arr"; int idx = requestedIndex;
Object arr = w.getPropertyValue(base);
int len = arr == null ? 0 : java.lang.reflect.Array.getLength(arr);
if (idx < 0 || idx >= len) {
w.setAutoGrowNestedPaths(true);
w.setAutoGrowCollectionLimit(Math.max(w.getAutoGrowCollectionLimit(), idx + 1));
}
w.setPropertyValue(base + "[" + idx + "]", value); Type guard
static boolean inArrayBounds(Object array, int idx) {
return array != null && array.getClass().isArray() && idx >= 0 && idx < java.lang.reflect.Array.getLength(array);
} Try / catch
try {
wrapper.setPropertyValue("arr[" + idx + "]", v);
} catch (InvalidPropertyException ex) {
if (ex.getCause() instanceof IndexOutOfBoundsException) { /* pre-size array or raise 400 */ }
else throw ex;
} Prevention
- Pre-size arrays to the max expected index.
- Set a sensible autoGrowCollectionLimit; reject indices beyond it at the controller.
- Prefer List/Map over arrays for user-driven indices.
When it happens
Trigger: setProperty("arr[3000]", value) with default autoGrowCollectionLimit=256; or autoGrowNestedPaths=false and arr.length <= index.
Common situations: Form binding array-indexed fields with sparse/large indices; autoGrow disabled explicitly; autoGrowCollectionLimit lowered; client sending an out-of-range index.
Related errors
- Invalid property ' ' of bean class [ ]: Index of out of…
- Cannot access indexed value in property referenced in…
- Cannot get element with index
- Cannot get element with index
- Cannot set element with index
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/102f3f60d4975869.
Report an issue: GitHub.
Appendix: source
Thrown at spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java:295
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);
System.arraycopy(propValue, 0, newArray, 0, length);
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
String propName = tokens.canonicalName.substring(0, lastKeyIndex);
setPropertyValue(propName, newArray);
propValue = getPropertyValue(propName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,
"Invalid array index in property path '" + tokens.canonicalName + "'", ex);
}
}
else if (propValue instanceof List list) {
TypeDescriptor requiredType = ph.getCollectionType(tokens.keys.length);
int index = Integer.parseInt(lastKey);
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),
requiredType.getResolvableType().resolve(), requiredType);
int size = list.size();
if (index >= size && index < getAutoGrowCollectionLimit()) {
for (int i = size; i < index; i++) {
try {
list.add(null);View on GitHub (pinned to 69bf83ad71)