spring-projects/spring-framework · error · NullValueInNestedPathException
Invalid property '{propertyName}' of bean class [{beanClass.
Error message
Invalid property '{propertyName}' of bean class [{beanClass.getName()}]: Value of nested property '{propertyName}' is null What it means
Thrown as NullValueInNestedPathException (subclass of InvalidPropertyException) by getNestedPropertyAccessor at AbstractNestablePropertyAccessor.java:836 when navigating a nested property path and an intermediate property resolves to null while autoGrowNestedPaths is disabled. The default message 'Value of nested property ... is null' comes from the NullValueInNestedPathException(beanClass, propertyName) constructor.
Source
Thrown at spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java:836
* @param nestedProperty property to create the PropertyAccessor for
* @return the PropertyAccessor instance, either cached or newly created
*/
private AbstractNestablePropertyAccessor getNestedPropertyAccessor(String nestedProperty) {
Map<String, AbstractNestablePropertyAccessor> nestedAccessors = this.nestedPropertyAccessors;
if (nestedAccessors == null) {
nestedAccessors = new HashMap<>();
this.nestedPropertyAccessors = nestedAccessors;
}
// Get value of bean property.
PropertyTokenHolder tokens = getPropertyNameTokens(nestedProperty);
String canonicalName = tokens.canonicalName;
Object value = getPropertyValue(tokens);
if (value == null || (value instanceof Optional<?> optional && optional.isEmpty())) {
if (isAutoGrowNestedPaths()) {
value = setDefaultValue(tokens);
}
else {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + canonicalName);
}
}
// Lookup cached sub-PropertyAccessor, create new one if not found.
AbstractNestablePropertyAccessor nestedPa = nestedAccessors.get(canonicalName);
if (nestedPa == null || nestedPa.getWrappedInstance() != ObjectUtils.unwrapOptional(value)) {
if (logger.isTraceEnabled()) {
logger.trace("Creating new nested " + getClass().getSimpleName() + " for property '" + canonicalName + "'");
}
nestedPa = newNestedPropertyAccessor(value, this.nestedPath + canonicalName + NESTED_PROPERTY_SEPARATOR);
// Inherit all type-specific PropertyEditors.
copyDefaultEditorsTo(nestedPa);
copyCustomEditorsTo(nestedPa, canonicalName);
nestedAccessors.put(canonicalName, nestedPa);
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Using cached nested property accessor for property '" + canonicalName + "'");View on GitHub (pinned to 69bf83ad71)
Solutions
- Initialize the nested reference in the bean's field declaration or constructor (e.g. 'private Address address = new Address();').
- Enable auto-growing: beanWrapper.setAutoGrowNestedPaths(true); to have Spring instantiate null intermediate beans.
- Provide the full nested object graph in the input rather than only the leaf value.
- Validate the path with isReadableProperty/getPropertyType before traversal and skip if the parent is null.
Example fix
// before
public class Person {
private Address address; // null
}
// after
public class Person {
private Address address = new Address();
} Defensive patterns
Strategy: validation
Validate before calling
// Pre-check that every intermediate segment is non-null
BeanWrapper w = new BeanWrapperImpl(target);
if (w.isAutoGrowNestedPaths() || intermediateNotNull(w, path)) {
w.getPropertyValue(path);
}
static boolean intermediateNotNull(BeanWrapper w, String path) {
String[] segs = path.split("\\.");
Object cur = w.getWrappedInstance();
BeanWrapper tmp = new BeanWrapperImpl(cur);
for (String s : segs) {
cur = tmp.getPropertyValue(s);
if (cur == null) return false;
tmp = new BeanWrapperImpl(cur);
}
return true;
} Type guard
static boolean canNavigate(Object root, String path) {
try {
Object cur = root;
for (String s : path.split("\\.")) {
cur = new BeanWrapperImpl(cur).getPropertyValue(s);
if (cur == null) return false;
}
return true;
} catch (BeansException e) { return false; }
} Try / catch
try {
wrapper.getPropertyValue("spouse.age");
} catch (NullValueInNestedPathException ex) {
// ex.getPropertyName() tells you which segment was null
// decide: skip, default, or enable auto-grow
wrapper.setAutoGrowNestedPaths(true);
} Prevention
- Initialize nested fields inline: 'private Address address = new Address();'.
- Enable setAutoGrowNestedPaths(true) when binding form data with sparse parents.
- Use isReadableProperty/getPropertyType to verify paths before traversal.
- Keep nested types as concrete instantiable classes with no-arg constructors.
When it happens
Trigger: Reading or writing a nested path such as 'spouse.age' or 'address.city' via BeanWrapper/PropertyAccessor when the intermediate 'spouse' or 'address' property is null and setAutoGrowNestedPaths(false) (the default). Also triggered when an intermediate Optional is empty (line 831 handles Optional.empty).
Common situations: Spring data binding from a form/JSON where only a leaf field is provided but the parent object is never initialized; @ConfigurationProperties binding into a DTO with nested objects that have no default initializer; SpEL/path traversal over a freshly constructed bean; entity graphs where a relation is lazily null.
Related errors
- Invalid property '{propertyName}' of bean class [{beanClass.
- Invalid property '{propertyName}' of bean class [{beanClass.
- Nested property in path '{propertyName}' does not exist
- Cannot access indexed value in property referenced in indexe
- Invalid property '{propertyName}' of bean class [{beanClass.
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/817b308e60f802df.
Report an issue: GitHub.