hibernate/hibernate-orm · critical · UnsupportedOperationException
CteMutationStrategy can only be used with Dialects that supp
Error message
CteMutationStrategy can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well
What it means
CteMutationStrategy implements bulk UPDATE/DELETE for multi-table entities via data-modifying CTEs and likewise requires Dialect.supportsNonQueryWithCTE() (true only on PostgreSQL, CockroachDB, SQL Server, DB2). Forcing this strategy on any other dialect throws UnsupportedOperationException while the SessionFactory is built, so the application fails to start.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteMutationStrategy.java:72
private final SessionFactoryImplementor sessionFactory;
private final CteTable idCteTable;
public CteMutationStrategy(
EntityMappingType rootEntityType,
RuntimeModelCreationContext runtimeModelCreationContext) {
this( rootEntityType.getEntityPersister(), runtimeModelCreationContext );
}
public CteMutationStrategy(
EntityPersister rootDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
this.rootDescriptor = rootDescriptor;
this.sessionFactory = runtimeModelCreationContext.getSessionFactory();
final Dialect dialect = runtimeModelCreationContext.getDialect();
if ( !dialect.supportsNonQueryWithCTE() ) {
throw new UnsupportedOperationException(
getClass().getSimpleName() +
" can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well"
);
}
this.idCteTable = CteTable.createIdTable( ID_TABLE_NAME,
runtimeModelCreationContext.getMetadata().getEntityBinding( rootDescriptor.getEntityName() ) );
}
@Override
public MultiTableHandlerBuildResult buildHandler(SqmDeleteOrUpdateStatement<?> sqmStatement, DomainParameterXref domainParameterXref, DomainQueryExecutionContext context) {
final MutableObject<JdbcParameterBindings> firstJdbcParameterBindings = new MutableObject<>();
final MultiTableHandler multiTableHandler = sqmStatement instanceof SqmDeleteStatement<?> sqmDelete
? buildHandler( sqmDelete, domainParameterXref, context, firstJdbcParameterBindings)
: buildHandler( (SqmUpdateStatement<?>) sqmStatement, domainParameterXref, context, firstJdbcParameterBindings );
return new MultiTableHandlerBuildResult( multiTableHandler, firstJdbcParameterBindings.get() );
}
View on GitHub (pinned to fad1729dce)
Solutions
- Drop the forced `hibernate.query.mutation_strategy=cte` property on non-CTE databases
- Scope CTE strategy settings to per-dialect configuration profiles
- Verify at bootstrap: only build with the CTE strategy when the configured dialect reports supportsNonQueryWithCTE()
Example fix
# before (application.properties, MySQL deployment) spring.jpa.properties.hibernate.query.mutation_strategy=cte # after # removed; Hibernate auto-selects a strategy the dialect supports
Defensive patterns
Strategy: validation
Validate before calling
// Profile-scoped config: enable CTE mutation strategy only when supported
Dialect d = (Dialect) Class.forName(configuredDialect)
.getDeclaredConstructor().newInstance();
if (!d.supportsNonQueryWithCTE()) {
properties.remove("hibernate.query.mutation_strategy");
} Try / catch
try {
emf = new Configuration().configure().buildSessionFactory();
} catch (HibernateException e) {
if (e.getCause() instanceof UnsupportedOperationException uoe
&& uoe.getMessage().contains("CteMutationStrategy")) {
throw new ConfigurationError(
"Drop hibernate.query.mutation_strategy=cte for this dialect", e);
}
throw e;
} Prevention
- Keep mutation-strategy settings in per-database profiles, not global baselines
- Audit shared config libraries for hibernate.query.mutation_strategy when onboarding MySQL
- Boot the SessionFactory in a smoke test so startup failures surface in CI
When it happens
Trigger: Configuring `hibernate.query.mutation_strategy=cte` on MySQL/MariaDB (or any dialect without data-modifying CTEs); auto-selecting mutation strategies based on a global property rather than the actual database.
Common situations: Same family as CteInsertStrategy: config snippets for PostgreSQL upsert/bulk-DML performance pasted into projects later deployed on MySQL; multi-environment deployments sharing one properties file; version upgrades where the setting became applicable to more statement types.
Related errors
- CteInsertStrategy can only be used with Dialects that suppor
- Assignment referred to column of a joined association: ${col
- Assignment referred to columns from multiple tables
- Unable to resolve name [{}] as strategy [{}]
- Can't use this method on for strategy types which are embedd
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e92da77e1f5539d5.
Report an issue: GitHub.