{"record":{"id":"203a0c54194253e0","repo":"hibernate/hibernate-orm","slug":"expecting-a-restricted-mutation-query-s-but-fo","errorCode":null,"errorMessage":"Expecting a restricted mutation query [%s], but found %s","messagePattern":"Expecting a restricted mutation query \\[(.+?)\\], but found (.+?)","errorType":"exception","errorClass":"IllegalMutationQueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java","lineNumber":203,"sourceCode":"\t\t}\n\t}\n\n\tpublic static IllegalQueryOperationException expectingNonSelect(SqmStatement<?> sqm, String hqlString) {\n\t\treturn new IllegalQueryOperationException(\n\t\t\t\tString.format(\n\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\"Expecting a non-SELECT Query [%s], but found %s\",\n\t\t\t\t\t\tSqmDmlStatement.class.getName(),\n\t\t\t\t\t\tsqm.getClass().getName()\n\t\t\t\t),\n\t\t\t\thqlString,\n\t\t\t\tnull\n\t\t);\n\t}\n\n\tpublic static void verifyIsRestrictedMutation(SqmStatement<?> sqm, String hqlString) {\n\t\tif ( ! isRestrictedMutation( sqm ) ) {\n\t\t\tthrow new IllegalMutationQueryException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Expecting a restricted mutation query [%s], but found %s\",\n\t\t\t\t\t\t\tSqmDeleteOrUpdateStatement.class.getName(),\n\t\t\t\t\t\t\tsqm.getClass().getName()\n\t\t\t\t\t),\n\t\t\t\t\thqlString\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic static @Nullable String determineAffectedTableName(TableGroup tableGroup, ValuedModelPart mapping) {\n\t\treturn tableGroup.getModelPart() instanceof EntityAssociationMapping associationMapping\n\t\t\t&& !associationMapping.containsTableReference( mapping.getContainingTableExpression() )\n\t\t\t\t? associationMapping.getAssociatedEntityMappingType().getMappedTableDetails().getTableName()\n\t\t\t\t: null;\n\t}\n","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java#L185-L221","documentation":"Thrown by SqmUtil.verifyIsRestrictedMutation as IllegalMutationQueryException when the SQM statement is not an SqmDeleteOrUpdateStatement. A 'restricted mutation' is an UPDATE or DELETE targeting one entity; the check is stricter than the generic non-select check (verifyIsNonSelectStatement), so anything that is not exactly a delete/update statement — a SELECT, or an INSERT-style statement such as 'insert into ... select' — is rejected. It is Hibernate's guard for execution paths that semantically require an entity-restricted UPDATE/DELETE.","triggerScenarios":"Calling executeUpdate()/mutation execution on a query whose SQM statement is a select (e.g. em.createQuery(\"select p from Person p\").executeUpdate()); feeding an HQL 'insert into Archive(a) select ...' into an API path that validates with verifyIsRestrictedMutation and therefore accepts only SqmDeleteOrUpdateStatement; reusing a query-template string for both insert-based copies and delete/update maintenance.","commonSituations":"Shared query templates where a SELECT leaks into a mutation path; copy-refresh logic written with insert-select that is later routed through a delete/update-only API; dynamic query builders that assemble the statement kind from configuration; migrating raw SQL batches to HQL mutation statements.","solutions":["Use UPDATE or DELETE HQL with the mutation API for paths that require a restricted mutation","Use a SelectionQuery (getResultList/getSingleResult) for SELECT statements","For HQL INSERT statements, route through the general mutation API that accepts inserts (createMutationQuery(...).executeUpdate()) instead of the restricted path","If you maintain the HQL externally, validate its first keyword before dispatching to the restricted-mutation code path"],"exampleFix":"// before\nint n = em.createQuery(\"select p from Person p\", Person.class).executeUpdate();\n// after\nList<Person> all = em.createQuery(\"select p from Person p\", Person.class).getResultList();","handlingStrategy":"validation","validationCode":"static boolean isRestrictedMutationHql(String hql) {\n    String head = hql.stripLeading().toLowerCase(Locale.ROOT);\n    return head.startsWith(\"update\") || head.startsWith(\"delete\");\n}\n\nif (!isRestrictedMutationHql(hql)) {\n    throw new IllegalArgumentException(\"Only UPDATE/DELETE allowed here: \" + hql);\n}","typeGuard":null,"tryCatchPattern":"try {\n    int n = session.createMutationQuery(hql).executeUpdate();\n} catch (IllegalMutationQueryException e) {\n    // statement is not an UPDATE/DELETE: reject before any side effects\n    throw new IllegalStateException(\"Restricted-mutation endpoint got a non-UPDATE/DELETE statement\", e);\n}","preventionTips":["Validate the statement keyword before calling executeUpdate-style APIs","Do not reuse one query-template string for SELECT and mutation paths","Cover insert-select copies with dedicated methods that use the general mutation API"],"tags":["hibernate","hql","mutation-query","executeupdate","orm"],"backgroundTag":"query-statement-type-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}