spring-projects/spring-framework · error · NullValueInNestedPathException
Value of nested property '${nestedPath}${canonicalName}' is
Error message
Value of nested property '${nestedPath}${canonicalName}' is null What it means
Thrown as NullValueInNestedPathException by AbstractNestablePropertyAccessor when resolving a nested property path (e.g. 'address.city') and an intermediate segment is null while auto-grow-nested-paths is disabled. Spring refuses to silently descend into null because it cannot obtain a BeanWrapper for the missing intermediate bean. The path string in the message is the accumulated nested path plus the canonical property name.
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 e8729d0438)
Solutions
- Initialize the nested property in the target class (e.g. private Address address = new Address();) so the path is never null.
- Enable auto-grow: wrapper.setAutoGrowNestedPaths(true) or set 'spring.databinding.auto-grow-nested-paths=true' where supported, so Spring creates intermediate instances.
- Bind a non-null instance before setting nested values, or restructure the bean so the intermediate is set at construction.
- Catch NullValueInNestedPathException around binding and report a user-facing validation error instead of propagating.
Example fix
// before
Order order = new Order(); // order.address == null
BeanWrapper w = new BeanWrapperImpl(order);
w.setPropertyValue("address.city", "NYC"); // -> NullValueInNestedPathException
// after (initialize nested bean)
public class Order { private Address address = new Address(); }
// or: w.setAutoGrowNestedPaths(true); Defensive patterns
Strategy: validation
Validate before calling
// Before binding a nested path, ensure intermediates are non-null
public static void ensurePath(Object root, String... props) throws Exception {
Object cur = root;
StringBuilder path = new StringBuilder();
for (String p : props) {
path.append(p).append('.');
PropertyDescriptor pd = Arrays.stream(
Introspector.getBeanInfo(cur.getClass()).getPropertyDescriptors())
.filter(d -> d.getName().equals(p)).findFirst().orElseThrow();
Object next = pd.getReadMethod().invoke(cur);
if (next == null) {
Object made = pd.getPropertyType().getDeclaredConstructor().newInstance();
pd.getWriteMethod().invoke(cur, made);
next = made;
}
cur = next;
}
} Type guard
public static boolean isNestedPathResolvable(BeanWrapper w, String path) {
try { return w.getPropertyValue(path) != null || w.isAutoGrowNestedPaths(); }
catch (NullValueInNestedPathException e) { return false; }
} Try / catch
try {
wrapper.setPropertyValue("address.city", value);
} catch (NullValueInNestedPathException e) {
// surface as a binding/validation error: "missing intermediate for " + e.getPropertyName()
} Prevention
- Initialize nested fields at declaration (private Address address = new Address();).
- Enable setAutoGrowNestedPaths(true) when binding dynamic graphs.
- Validate the command bean's nested fields are non-null in an @InitBinder or validator.
When it happens
Trigger: Calling BeanWrapperImpl.setPropertyValue('a.b.c', val) / DataBinder binding when the target's 'a' (or 'a.b') field is null and wrapper.setAutoGrowNestedPaths(false) (the default). Also triggered by getNestedPropertyAccessor when reading a nested path whose value is null or an empty Optional.
Common situations: Binding a form-backing bean where the nested object was never initialized (e.g. new Order() with a null Address). YAML/properties binding into a graph that has null intermediate references. Spring MVC form binding to a command object whose nested entity field is null.
Related errors
- Nested property in path '{propertyName}' does not exist
- Cannot access indexed value in property referenced in indexe
- Cannot access indexed value in property referenced in indexe
- Cannot access indexed value of property referenced in indexe
- Could not determine property type for auto-growing a default
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/d37d7d34d540c3e4.json.
Report an issue: GitHub.