hibernate/hibernate-orm · error · InstantiationException

Cannot set field '{}' to instantiate '{}'

Error message

Cannot set field '{}' to instantiate '{}'

What it means

For injection-style dynamic instantiation (select new with a no-arg-constructible target), DynamicInstantiationAssemblerInjectionImpl.injection() tries, per argument, first a matching JavaBean property (name plus compatible type via propertyMatches) and then a field with the alias name and compatible type (findField). If neither exists for an argument's alias, it throws InstantiationException("Cannot set field '<alias>' to instantiate '<target class>'") at query-plan build time: the query aliases do not line up with any setter or field on the target.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationAssemblerInjectionImpl.java:75

		final var argType = argument.getAssembledJavaType().getJavaTypeClass();
		final String alias = argument.getAlias();

		// see if we can find a property with the given name...
		for ( var propertyDescriptor : beanInfo.getPropertyDescriptors() ) {
			if ( propertyMatches( alias, argType, propertyDescriptor ) ) {
				final var setter = propertyDescriptor.getWriteMethod();
				setter.setAccessible(true);
				return new BeanInjection( new BeanInjectorSetter<>( setter ), argument );
			}
		}

		// see if we can find a Field with the given name...
		final var field = findField( targetJavaType, alias, argType );
		if ( field != null ) {
			return new BeanInjection( new BeanInjectorField<>( field ), argument );
		}
		else {
			throw new InstantiationException(
					"Cannot set field '" + alias + "' to instantiate '" + targetJavaType.getName() + "'"
			);
		}
	}

	@Override
	public JavaType<T> getAssembledJavaType() {
		return target;
	}

	@Override
	@SuppressWarnings("unchecked")
	public T assemble(RowProcessingState rowProcessingState) {
		final T result;
		try {
			final var constructor = target.getJavaTypeClass().getDeclaredConstructor();
			constructor.setAccessible( true );
			result = constructor.newInstance();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Make every select-item alias match, by name and type, a setter (or field) on the target class - exact spelling and an assignable type.
  2. Add the missing property (field plus setter) with the aliased name, or rename the alias in the query to the existing property.
  3. If types cannot match, switch to a constructor expression with an explicit constructor for full control.
  4. Cover every dynamic-instantiation query with a startup smoke test (createQuery plus execution on test data) so the failure is caught at build time, not production.

Example fix

// before
public class EmpDto { private String fullName; /* no 'nm' */ }
em.createQuery("select new com.acme.EmpDto(e.name as nm) from Employee e", EmpDto.class);
// -> Cannot set field 'nm' to instantiate 'com.acme.EmpDto'

// after
em.createQuery("select new com.acme.EmpDto(e.name as fullName) from Employee e", EmpDto.class);
Defensive patterns

Strategy: validation

Validate before calling

// At startup, verify every query alias has a matching, type-compatible setter or field
Set<String> props = new HashSet<>();
for (PropertyDescriptor pd : Introspector.getBeanInfo(EmpDto.class).getPropertyDescriptors())
    if (pd.getWriteMethod() != null) props.add(pd.getName());
for (Field f : EmpDto.class.getDeclaredFields()) props.add(f.getName());
for (String alias : List.of("fullName" /* aliases used in the query */)) {
    if (!props.contains(alias))
        throw new IllegalStateException("alias '" + alias + "' has no setter/field on EmpDto");
}

Type guard

// Reflective guard: alias must resolve to an injectable member
static boolean aliasInjectable(Class<?> dto, String alias, Class<?> assembled) {
    try {
        for (PropertyDescriptor pd : Introspector.getBeanInfo(dto).getPropertyDescriptors())
            if (pd.getName().equals(alias) && pd.getWriteMethod() != null
                    && pd.getWriteMethod().getParameterTypes()[0].isAssignableFrom(assembled))
                return true;
        return dto.getDeclaredField(alias).getType().isAssignableFrom(assembled);
    } catch (IntrospectionException | NoSuchFieldException e) { return false; }
}

Try / catch

try {
    rows = q.getResultList();
} catch (org.hibernate.query.sqm.sql.internal.InstantiationException e) {
    if (String.valueOf(e.getMessage()).startsWith("Cannot set field '")) {
        // the message names the bad alias and target class: add the property or fix the alias
    }
}

Prevention

When it happens

Trigger: `select new com.acme.Dto(o.name as nm, o.age as yrs) ...` where Dto has no setNm/nm field and no setYrs/yrs field; alias matches a property but the argument type is incompatible, so the property check fails AND no same-named field with the right type exists (type compatibility is part of matching); typos or casing mismatches between alias and property name.

Common situations: Renaming DTO properties or query aliases independently; adding a new select item with an alias the DTO never got; alias/property type drift after model changes (e.g. property changed from int to String so propertyMatches no longer accepts); query and DTO updated in different commits.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/9b2b1b8d889562db. Report an issue: GitHub.