{"id":"0436f091d354c8fa","repo":"spring-projects/spring-framework","slug":"property-referenced-in-indexed-property-path-tok","errorCode":null,"errorMessage":"Property referenced in indexed property path '{tokens.canonicalName}' is neither an array nor a List nor a Map; returned value was [{propValue}]","messagePattern":"Property referenced in indexed property path '(.+?)' is neither an array nor a List nor a Map; returned value was \\[(.+?)\\]","errorType":"exception","errorClass":"InvalidPropertyException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java","lineNumber":354,"sourceCode":"\t\t\tTypeDescriptor mapKeyType = ph.getMapKeyType(tokens.keys.length);\n\t\t\tTypeDescriptor mapValueType = ph.getMapValueType(tokens.keys.length);\n\t\t\t// IMPORTANT: Do not pass full property name in here - property editors\n\t\t\t// must not kick in for map keys but rather only for map values.\n\t\t\tObject convertedMapKey = convertIfNecessary(null, null, lastKey,\n\t\t\t\t\tmapKeyType.getResolvableType().resolve(), mapKeyType);\n\t\t\tObject oldValue = null;\n\t\t\tif (isExtractOldValueForEditor()) {\n\t\t\t\toldValue = map.get(convertedMapKey);\n\t\t\t}\n\t\t\t// Pass full property name and old value in here, since we want full\n\t\t\t// conversion ability for map values.\n\t\t\tObject convertedMapValue = convertIfNecessary(tokens.canonicalName, oldValue, pv.getValue(),\n\t\t\t\t\tmapValueType.getResolvableType().resolve(), mapValueType);\n\t\t\tmap.put(convertedMapKey, convertedMapValue);\n\t\t}\n\n\t\telse {\n\t\t\tthrow new InvalidPropertyException(getRootClass(), this.nestedPath + tokens.canonicalName,\n\t\t\t\t\t\"Property referenced in indexed property path '\" + tokens.canonicalName +\n\t\t\t\t\t\"' is neither an array nor a List nor a Map; returned value was [\" + propValue + \"]\");\n\t\t}\n\t}\n\n\tprivate Object getPropertyHoldingValue(PropertyTokenHolder tokens) {\n\t\t// Apply indexes and map keys: fetch value for all keys but the last one.\n\t\tAssert.state(tokens.keys != null, \"No token keys\");\n\t\tPropertyTokenHolder getterTokens = new PropertyTokenHolder(tokens.actualName);\n\t\tgetterTokens.canonicalName = tokens.canonicalName;\n\t\tgetterTokens.keys = new String[tokens.keys.length - 1];\n\t\tSystem.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);\n\n\t\tObject propValue;\n\t\ttry {\n\t\t\tpropValue = getPropertyValue(getterTokens);\n\t\t}\n\t\tcatch (NotReadablePropertyException ex) {","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java#L336-L372","documentation":"Thrown in the final else of processKeyedProperty: the property path uses index/map syntax (e.g. 'foo[0]' or 'foo[key]') but the resolved value is not an array, List, or Map. Because there is no keyed access possible, Spring raises InvalidPropertyException naming the canonical path and showing the offending value.","triggerScenarios":"setProperty(\"count[0]\", x) where getCount() returns an int; binding 'name[key]' onto a String property; a path where the collection field was replaced by a scalar type in a refactor.","commonSituations":"Binding indexed form fields onto a bean whose property is a scalar after a model change; SpEL/BeanWrapper misuse applying brackets to non-collection fields; misconfigured @ConfigurationProperties mapping a list key onto a single-value field.","solutions":["Change the bean property to an array, List, or Map so indexed/mapped writes are valid.","Remove the index/bracket from the path if the target is genuinely scalar.","Re-check the path spelling and ensure the intended collection property is being addressed."],"exampleFix":"// before\npublic class Cart { private int itemCount; ... }\nwrapper.setPropertyValue(\"itemCount[0]\", 1); // scalar, not indexable\n\n// after\npublic class Cart { private List<Integer> itemCounts = new ArrayList<>(); ... }\nwrapper.setPropertyValue(\"itemCounts[0]\", 1);","handlingStrategy":"type-guard","validationCode":"Class<?> type = wrapper.getPropertyType(\"count\");\nif (type != null && (type.isArray() || List.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type))) {\n    wrapper.setPropertyValue(\"count[0]\", value);\n}","typeGuard":"static boolean isIndexable(Class<?> type) {\n    return type != null && (type.isArray() || List.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type));\n}","tryCatchPattern":"try { wrapper.setPropertyValue(path, value); }\ncatch (InvalidPropertyException ex) { /* property is scalar; drop bracket */ }","preventionTips":["Check the property type is array/List/Map before applying bracket syntax.","Keep binding paths consistent with the current model types."],"tags":["spring-beans","bean-wrapper","indexed-property","type-mismatch"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}