spring-projects/spring-framework · error · NullValueInNestedPathException

Invalid property '{propertyName}' of bean class [{beanClass.

Error message

Invalid property '{propertyName}' of bean class [{beanClass.getName()}]: Could not instantiate property type [{type.getName()}] to auto-grow nested property path

What it means

Thrown as NullValueInNestedPathException by newValue() at AbstractNestablePropertyAccessor.java:900 when auto-growing requires instantiating a default value for a nested property but BeanUtils.instantiateClass(ctor) (or array/collection creation) fails. The message names the target type that could not be instantiated. The catch is `catch (Throwable ex)`, so it also catches private-constructor IllegalAccessException raised earlier in newValue (line 894).

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java:900

			}
			else if (Collection.class.isAssignableFrom(type)) {
				TypeDescriptor elementDesc = (desc != null ? desc.getElementTypeDescriptor() : null);
				return CollectionFactory.createCollection(type, (elementDesc != null ? elementDesc.getType() : null), 16);
			}
			else if (Map.class.isAssignableFrom(type)) {
				TypeDescriptor keyDesc = (desc != null ? desc.getMapKeyTypeDescriptor() : null);
				return CollectionFactory.createMap(type, (keyDesc != null ? keyDesc.getType() : null), 16);
			}
			else {
				Constructor<?> ctor = type.getDeclaredConstructor();
				if (Modifier.isPrivate(ctor.getModifiers())) {
					throw new IllegalAccessException("Auto-growing not allowed with private constructor: " + ctor);
				}
				return BeanUtils.instantiateClass(ctor);
			}
		}
		catch (Throwable ex) {
			throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
					"Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);
		}
	}

	/**
	 * Create the array for the given array type.
	 * @param arrayType the desired type of the target array
	 * @return a new array instance
	 */
	private static Object createArray(Class<?> arrayType) {
		Assert.notNull(arrayType, "Array type must not be null");
		Class<?> componentType = arrayType.componentType();
		if (componentType.isArray()) {
			Object array = Array.newInstance(componentType, 1);
			Array.set(array, 0, createArray(componentType));
			return array;
		}
		else {

View on GitHub (pinned to 69bf83ad71)

Solutions

  1. Change the nested field type to a concrete instantiable class with a no-arg constructor.
  2. Add a public/protected no-arg constructor to the nested type (avoid private, which newValue explicitly rejects).
  3. Make nested classes static (non-inner) so they can be instantiated without an enclosing instance.
  4. If the type legitimately cannot be auto-instantiated, initialize it in the field declaration and turn off auto-grow for that path.

Example fix

// before: interface field type, cannot be auto-grown
public class Order {
    private Discount discount; // Discount is an interface
}

// after: concrete type with no-arg ctor
public class Order {
    private PercentageDiscount discount = new PercentageDiscount();
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify a nested type is concrete & instantiable before auto-growing
Class<?> t = wrapper.getPropertyTypeDescriptor("nested").getType();
boolean ok = !t.isInterface() && !Modifier.isAbstract(t.getModifiers())
    && !t.isPrimitive() && !t.isArray();
try { t.getDeclaredConstructor(); } catch (NoSuchMethodException e) { ok = false; }
if (!ok) wrapper.setAutoGrowNestedPaths(false);

Type guard

static boolean instantiableNoArg(Class<?> t) {
    if (t.isInterface() || Modifier.isAbstract(t.getModifiers())) return false;
    try {
        Constructor<?> c = t.getDeclaredConstructor();
        return !Modifier.isPrivate(c.getModifiers());
    } catch (NoSuchMethodException e) { return false; }
}

Try / catch

try {
    wrapper.setAutoGrowNestedPaths(true);
    wrapper.getPropertyValue("nested.value");
} catch (NullValueInNestedPathException ex) {
    if (ex.getCause() != null) {
        // instantiation failed — type not usable for auto-grow
        // initialize the field explicitly instead
    }
}

Prevention

When it happens

Trigger: Auto-grow (setAutoGrowNestedPaths true) traverses into a nested property whose declared type has no public/default no-arg constructor, is an interface/abstract type used as a field type, has a private constructor, or whose constructor throws on instantiation. Also fires if creating the array/Collection/Map via CollectionFactory fails.

Common situations: Declaring a nested field as an interface or abstract type (List vs ArrayList is fine, but a custom interface field type is not); nested type with only a required-args constructor; nested type that is an inner non-static class needing an enclosing instance; classpath/LinkageError while instantiating; Kotlin/record types without a usable canonical constructor.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/21aa657e3bf32a7b. Report an issue: GitHub.