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
- Call from() with the same class/entity you passed to createCriteriaUpdate/Delete/InsertSelect.
- Skip from() entirely: use getRoot() / getTarget() on the DML statement to obtain the root.
- 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
- In generic DML code, derive the root with getRoot()/getTarget() instead of from().
- Create the statement and its from() from one Class<E> variable.
- Remember the check is by reference: use EntityType objects from the same SessionFactory/metamodel.
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
- Illegal empty CTE name
- Illegal CTE name [%s]. Names must start with an alphabetic c
- DELETE query cannot be sub-query
- Passed attribute name [%s] did not correspond to a collectio
- Passed attribute name [%s] did not correspond to a collectio
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/7264060c5667172b.
Report an issue: GitHub.