hibernate/hibernate-orm · error · IllegalArgumentException

Expecting DML target entity type [%s] but got [%s]

Error message

Expecting DML target entity type [%s] but got [%s]

What it means

AbstractSqmRestrictedDmlStatement.from(EntityType) requires the passed EntityType to be the exact model of the DML target root (root.getModel() != entity is a reference comparison). Criteria insert/update/delete statements operate on exactly one entity, so from() only hands back the existing target root; passing any other entity type throws IllegalArgumentException showing the expected and the received entity names.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/AbstractSqmRestrictedDmlStatement.java:78

	protected @Nullable SqmWhereClause copyWhereClause(SqmCopyContext context) {
		if ( whereClause == null ) {
			return null;
		}
		else {
			final var predicate = whereClause.getPredicate();
			return new SqmWhereClause( predicate == null ? null : predicate.copy( context ), nodeBuilder() );
		}
	}

	public SqmRoot<T> from(Class<T> entityClass) {
		return from( nodeBuilder().getDomainModel().entity( entityClass ) );
	}

	public SqmRoot<T> from(EntityType<T> entity) {
		final var entityDomainType = (EntityDomainType<T>) entity;
		final var root = getTarget();
		if ( root.getModel() != entity ) {
			throw new IllegalArgumentException(
					String.format(
							"Expecting DML target entity type [%s] but got [%s]",
							root.getModel().getHibernateEntityName(),
							entityDomainType.getName()
					)
			);
		}
		return root;
	}

	public SqmRoot<T> getRoot() {
		return getTarget();
	}

	public @Nullable SqmWhereClause getWhereClause() {
		return whereClause;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call from() with the same class/entity you passed to createCriteriaUpdate/Delete/InsertSelect.
  2. Skip from() entirely: use getRoot() / getTarget() on the DML statement to obtain the root.
  3. In generic code, carry a single Class<E> parameter and use it for both statement creation and from().

Example fix

// before
CriteriaUpdate<Employee> update = cb.createCriteriaUpdate( Employee.class );
Root<Person> root = update.from( Person.class ); // throws
// after
Root<Employee> root = update.from( Employee.class ); // or update.getRoot()
Defensive patterns

Strategy: validation

Validate before calling

// before calling from():
EntityType<T> expected = (EntityType<T>) update.getRoot().getModel();
if ( expected != entity ) {
    throw new IllegalArgumentException(
        "DML target is " + expected.getName() + ", refusing from(" + entity.getName() + ")" );
}
Root<T> root = update.from( entity );

Type guard

static boolean isDmlTarget(AbstractSqmDmlStatement<?> dml, EntityType<?> candidate) {
    return dml.getRoot().getModel() == candidate; // reference equality, same as the check
}

Try / catch

try {
    root = update.from( entity );
} catch (IllegalArgumentException e) {
    if ( e.getMessage() != null && e.getMessage().startsWith( "Expecting DML target entity type" ) ) {
        root = update.getRoot(); // fall back to the real target root
    } else { throw e; }
}

Prevention

When it happens

Trigger: cb.createCriteriaUpdate(Person.class) followed by update.from(Employee.class) or update.from(otherMetamodel.entity(Person.class)); from(Class) resolving to a different entity than the one used in createCriteriaUpdate/createCriteriaDelete/createCriteriaInsertSelect.

Common situations: Copy-pasting a select-query pattern (where from() may be called with any entity) into a DML builder; generic DML helpers that take target and filter entities separately; two SessionFactories in tests supplying EntityType instances from different metamodels (reference inequality).

Related errors


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