hibernate/hibernate-orm · critical · UnsupportedOperationException
CteInsertStrategy can only be used with Dialects that suppor
Error message
CteInsertStrategy can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well
What it means
CteInsertStrategy implements multi-table inserts by chaining data-modifying CTEs, which the dialect must support (Dialect.supportsNonQueryWithCTE()). Only PostgreSQL, CockroachDB, SQL Server, and DB2 override it to true — MySQL/MariaDB do not. Constructing this strategy on an unsupported dialect throws UnsupportedOperationException during SessionFactory bootstrap, failing application startup.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteInsertStrategy.java:114
private final SessionFactoryImplementor sessionFactory;
private final CteTable entityCteTable;
public CteInsertStrategy(
EntityMappingType rootEntityType,
RuntimeModelCreationContext runtimeModelCreationContext) {
this( rootEntityType.getEntityPersister(), runtimeModelCreationContext );
}
public CteInsertStrategy(
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"
);
}
final PersistentClass persistentClass = runtimeModelCreationContext.getMetadata()
.getEntityBinding( rootDescriptor.getEntityName() );
final Identifier tableNameIdentifier;
if ( persistentClass instanceof SingleTableSubclass ) {
// In this case, the descriptor is a subclass of a single table inheritance.
// To avoid name collisions, we suffix the table name with the subclass number
tableNameIdentifier = new Identifier(
persistentClass.getTable().getNameIdentifier().getText() + persistentClass.getSubclassId(),
persistentClass.getTable().getNameIdentifier().isQuoted()
);
}
else {
tableNameIdentifier = persistentClass.getTable().getNameIdentifier();View on GitHub (pinned to fad1729dce)
Solutions
- Remove `hibernate.query.mutation_strategy=cte` and let Hibernate pick the table-based strategy automatically
- Keep the setting only in PostgreSQL/DB2/SQL Server/CockroachDB-specific configuration profiles
- Guard programmatically: enable the CTE strategy only if sessionFactory dialect.supportsNonQueryWithCTE() is true
Example fix
# before (persistence.xml on MySQL) <property name="hibernate.query.mutation_strategy" value="cte"/> # after <!-- removed: let Hibernate choose the strategy per dialect -->
Defensive patterns
Strategy: validation
Validate before calling
// Before forcing the strategy, check the dialect capability
Map<String, Object> props = new HashMap<>();
Dialect dialect = (Dialect) Class.forName(dialectClassName)
.getDeclaredConstructor().newInstance();
if (dialect.supportsNonQueryWithCTE()) {
props.put(AvailableSettings.QUERY_MUTATION_STRATEGY, "cte");
} Try / catch
try {
return Persistence.createEntityManagerFactory("pu", props);
} catch (PersistenceException e) {
if (e.getCause() instanceof UnsupportedOperationException uoe
&& uoe.getMessage().contains("support CTE")) {
throw new ConfigurationError("Remove hibernate.query.mutation_strategy=cte "
+ "— this database lacks data-modifying CTEs", e);
}
throw e;
} Prevention
- Only set hibernate.query.mutation_strategy=cte for PostgreSQL, DB2, SQL Server, CockroachDB
- MySQL/MariaDB cannot run UPDATE/DELETE inside CTEs — never force this strategy there
- Fail fast in CI by booting the SessionFactory against the production-like database
When it happens
Trigger: Setting `hibernate.query.mutation_strategy=cte` (AvailableSettings.QUERY_MUTATION_STRATEGY) in persistence.xml/application.properties while running MySQL/MariaDB; a global baseline config applied to all environments including non-CTE databases.
Common situations: Copying the popular `hibernate.query.mutation_strategy=cte` snippet (recommended for insert...select on PostgreSQL) into a MySQL project; switching the test/prod DB from PostgreSQL to MySQL without pruning Hibernate properties; the setting appearing in shared config libraries.
Related errors
- CteMutationStrategy can only be used with Dialects that supp
- The {storageEngine} storage engine is not supported
- Unable to resolve name [{}] as strategy [{}]
- Can't use this method on for strategy types which are embedd
- Default resolver threw exception
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c10c46a4a7da39ca.
Report an issue: GitHub.