{"id":"ce65561be06f0d41","repo":"spring-projects/spring-framework","slug":"bean-property-propertyname-is-not-readable-or","errorCode":null,"errorMessage":"Bean property '{propertyName}' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?","messagePattern":"Bean property '(.+?)' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter\\?","errorType":"exception","errorClass":"NotReadablePropertyException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java","lineNumber":603,"sourceCode":"\t\t\tthrows TypeMismatchException {\n\n\t\treturn convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);\n\t}\n\n\t@Override\n\tpublic @Nullable Object getPropertyValue(String propertyName) throws BeansException {\n\t\tAbstractNestablePropertyAccessor nestedPa = getPropertyAccessorForPropertyPath(propertyName);\n\t\tPropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));\n\t\treturn nestedPa.getPropertyValue(tokens);\n\t}\n\n\t@SuppressWarnings({\"rawtypes\", \"unchecked\"})\n\tprotected @Nullable Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {\n\t\tString propertyName = tokens.canonicalName;\n\t\tString actualName = tokens.actualName;\n\t\tPropertyHandler ph = getLocalPropertyHandler(actualName);\n\t\tif (ph == null || !ph.isReadable()) {\n\t\t\tthrow new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);\n\t\t}\n\t\ttry {\n\t\t\tObject value = ph.getValue();\n\t\t\tif (tokens.keys != null) {\n\t\t\t\tif (value == null) {\n\t\t\t\t\tif (isAutoGrowNestedPaths()) {\n\t\t\t\t\t\tvalue = setDefaultValue(new PropertyTokenHolder(tokens.actualName));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthrow new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,\n\t\t\t\t\t\t\t\t\"Cannot access indexed value of property referenced in indexed \" +\n\t\t\t\t\t\t\t\t\t\t\"property path '\" + propertyName + \"': returned null\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tStringBuilder indexedPropertyName = new StringBuilder(tokens.actualName);\n\t\t\t\t// apply indexes and map keys\n\t\t\t\tfor (int i = 0; i < tokens.keys.length; i++) {\n\t\t\t\t\tString key = tokens.keys[i];","sourceCodeStart":585,"sourceCodeEnd":621,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java#L585-L621","documentation":"The default message of NotReadablePropertyException, raised in getPropertyValue(PropertyTokenHolder) when getLocalPropertyHandler(actualName) returns null or reports !ph.isReadable(). The hint about getter/setter type mismatch refers to BeanWrapperIntrospection: a setter whose parameter type does not match the getter return type can cause the property to be treated as non-readable. So the property either does not exist or its accessor pair is inconsistent.","triggerScenarios":"wrapper.getPropertyValue(\"foo\") on a bean with no getFoo(); a bean where getFoo() returns String but setFoo(int) makes the pair inconsistent; accessing a write-only property for reading.","commonSituations":"Reading a property that only has a setter; model refactor renaming getters; binding/validation code that probes arbitrary property names; Kotlin data classes where a property is declared private.","solutions":["Confirm a public getter exists for the property and that its name matches JavaBean conventions.","Align the setter parameter type with the getter return type so the introspector treats the pair as consistent.","Use wrapper.isReadableProperty(name) before calling getPropertyValue to avoid the exception.","Correct the property name / check for typos."],"exampleFix":"// before\npublic class Person { private String name; public void setName(String n) { this.name = n; } }\nwrapper.getPropertyValue(\"name\"); // no getter\n\n// after\npublic String getName() { return name; }","handlingStrategy":"validation","validationCode":"if (wrapper.isReadableProperty(propertyName)) {\n    Object v = wrapper.getPropertyValue(propertyName);\n}","typeGuard":"static boolean hasConsistentGetterSetter(Class<?> bean, String name) {\n    try {\n        java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);\n        for (java.beans.PropertyDescriptor pd : info.getPropertyDescriptors()) {\n            if (pd.getName().equals(name)) {\n                return pd.getReadMethod() != null\n                    && (pd.getWriteMethod() == null\n                        || pd.getWriteMethod().getParameterTypes()[0] == pd.getReadMethod().getReturnType());\n            }\n        }\n        return false;\n    } catch (Exception ex) { return false; }\n}","tryCatchPattern":"try { Object v = wrapper.getPropertyValue(propertyName); }\ncatch (NotReadablePropertyException ex) { /* property has no usable getter */ }","preventionTips":["Always provide a public getter matching JavaBean conventions.","Keep setter parameter type == getter return type.","Call isReadableProperty before reading unfamiliar names."],"tags":["spring-beans","bean-wrapper","not-readable","getter","introspection"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}