hibernate/hibernate-orm · error · IllegalSelectQueryException
Expecting a SELECT Query [%s], but found %s
Error message
Expecting a SELECT Query [%s], but found %s
What it means
SqmUtil.asSelectStatement is the choke point where Hibernate asserts that an SQM statement it is about to treat as a query (typed results, scrolling, paging) really is an SqmSelectStatement. Passing an update/delete/insert statement — usually because HQL text like 'update ...' was handed to a select-oriented API — throws IllegalSelectQueryException with both class names in the message.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java:147
public static boolean isSelect(SqmStatement<?> sqm) {
return sqm instanceof SqmSelectStatement;
}
public static boolean isMutation(SqmStatement<?> sqm) {
return sqm instanceof SqmDmlStatement;
}
public static <T> boolean isRestrictedMutation(SqmStatement<T> sqmStatement) {
return sqmStatement instanceof SqmDeleteOrUpdateStatement;
}
public static <R> SqmSelectStatement<R> asSelectStatement(SqmStatement<?> sqm, String hqlString) {
if ( sqm instanceof SqmSelectStatement<?> selectAst ) {
//noinspection unchecked
return (SqmSelectStatement<R>) selectAst;
}
else {
throw new IllegalSelectQueryException(
String.format(
Locale.ROOT,
"Expecting a SELECT Query [%s], but found %s",
SqmSelectStatement.class.getName(),
sqm.getClass().getName()
),
hqlString
);
}
}
public static void verifyIsSelectStatement(SqmStatement<?> sqm, String hqlString) {
if ( ! isSelect( sqm ) ) {
throw new IllegalSelectQueryException(
String.format(
Locale.ROOT,
"Expecting a SELECT Query [%s], but found %s",
SqmSelectStatement.class.getName(),View on GitHub (pinned to fad1729dce)
Solutions
- Use the mutation API for non-select HQL: em.createMutationQuery(hql).executeUpdate() (Hibernate 6+) / session.createMutationQuery(...).
- If the statement should be a select, fix the HQL itself (missing 'select'/'from' clause, wrong keyword, truncated string).
- Branch on the first keyword of dynamic HQL before choosing createQuery vs createMutationQuery.
Example fix
// before
Query<Order> q = em.createQuery("update Order o set o.status = :s", Order.class);
q.getResultList(); // Expecting a SELECT Query [...], but found SqmUpdateStatement
// after
MutationQuery q = em.createMutationQuery("update Order o set o.status = :s").setParameter("s", "OPEN");
q.executeUpdate(); Defensive patterns
Strategy: validation
Validate before calling
static boolean isSelectHql(String hql) {
String head = hql.trim().toLowerCase(Locale.ROOT);
return head.startsWith("select") || head.startsWith("from");
}
if (!isSelectHql(hql)) throw new IllegalArgumentException("use createMutationQuery for: " + hql); Type guard
static boolean isMutationHql(String hql) {
String head = hql.trim().toLowerCase(Locale.ROOT);
return head.startsWith("update") || head.startsWith("delete") || head.startsWith("insert");
} Try / catch
try {
results = em.createQuery(hql, type).getResultList();
} catch (IllegalSelectQueryException e) {
// HQL was update/delete/insert: route to the mutation API instead
em.createMutationQuery(hql).executeUpdate();
} Prevention
- Route by statement type at one choke point: select/from -> createQuery, update/delete/insert -> createMutationQuery.
- Never pass user-supplied HQL straight into a typed createQuery without a keyword check.
- Prefer the criteria API for dynamic statements so the compiler fixes the statement type.
When it happens
Trigger: em.createQuery(hql, Order.class) where hql = 'update Order o set ...' (typed query creation implies select); session.createQuery(hql).getSingleResult() / setMaxResults / scroll on mutation HQL; feeding a mutation query through APIs like SQM copying or name-based typed lookups that internally call asSelectStatement.
Common situations: Concatenated/templated HQL that flips between select and bulk statements; DML statements routed to createQuery instead of createMutationQuery during refactors; migration from Hibernate 5 where some leniency existed; GUI query builders executing user-entered HQL.
Related errors
- Query string is not a mutation
- Incorrect query result type: query produces '%s' but type '%
- Expecting a restricted mutation query [%s], but found %s
- Could not resolve attribute '${name}' of any mapping (must b
- unrecognized cast target type: {}
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/32dfac48829daa0a.
Report an issue: GitHub.