{"record":{"id":"e92da77e1f5539d5","repo":"hibernate/hibernate-orm","slug":"ctemutationstrategy-can-only-be-used-with-dialects","errorCode":null,"errorMessage":"CteMutationStrategy can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well","messagePattern":"CteMutationStrategy can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"critical","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteMutationStrategy.java","lineNumber":72,"sourceCode":"\tprivate final SessionFactoryImplementor sessionFactory;\n\tprivate final CteTable idCteTable;\n\n\tpublic CteMutationStrategy(\n\t\t\tEntityMappingType rootEntityType,\n\t\t\tRuntimeModelCreationContext runtimeModelCreationContext) {\n\t\tthis( rootEntityType.getEntityPersister(), runtimeModelCreationContext );\n\t}\n\n\tpublic CteMutationStrategy(\n\t\t\tEntityPersister rootDescriptor,\n\t\t\tRuntimeModelCreationContext runtimeModelCreationContext) {\n\t\tthis.rootDescriptor = rootDescriptor;\n\t\tthis.sessionFactory = runtimeModelCreationContext.getSessionFactory();\n\n\t\tfinal Dialect dialect = runtimeModelCreationContext.getDialect();\n\n\t\tif ( !dialect.supportsNonQueryWithCTE() ) {\n\t\t\tthrow new UnsupportedOperationException(\n\t\t\t\t\tgetClass().getSimpleName() +\n\t\t\t\t\t\t\t\" can only be used with Dialects that support CTE that can take UPDATE or DELETE statements as well\"\n\t\t\t);\n\t\t}\n\n\t\tthis.idCteTable = CteTable.createIdTable( ID_TABLE_NAME,\n\t\t\t\truntimeModelCreationContext.getMetadata().getEntityBinding( rootDescriptor.getEntityName() ) );\n\t}\n\n\t@Override\n\tpublic MultiTableHandlerBuildResult buildHandler(SqmDeleteOrUpdateStatement<?> sqmStatement, DomainParameterXref domainParameterXref, DomainQueryExecutionContext context) {\n\t\tfinal MutableObject<JdbcParameterBindings> firstJdbcParameterBindings = new MutableObject<>();\n\t\tfinal MultiTableHandler multiTableHandler = sqmStatement instanceof SqmDeleteStatement<?> sqmDelete\n\t\t\t\t? buildHandler( sqmDelete, domainParameterXref, context, firstJdbcParameterBindings)\n\t\t\t\t: buildHandler( (SqmUpdateStatement<?>) sqmStatement, domainParameterXref, context, firstJdbcParameterBindings );\n\t\treturn new MultiTableHandlerBuildResult( multiTableHandler, firstJdbcParameterBindings.get() );\n\t}\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteMutationStrategy.java#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()"],"exampleFix":"# before (application.properties, MySQL deployment)\nspring.jpa.properties.hibernate.query.mutation_strategy=cte\n\n# after\n# removed; Hibernate auto-selects a strategy the dialect supports","handlingStrategy":"validation","validationCode":"// Profile-scoped config: enable CTE mutation strategy only when supported\nDialect d = (Dialect) Class.forName(configuredDialect)\n        .getDeclaredConstructor().newInstance();\nif (!d.supportsNonQueryWithCTE()) {\n    properties.remove(\"hibernate.query.mutation_strategy\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    emf = new Configuration().configure().buildSessionFactory();\n} catch (HibernateException e) {\n    if (e.getCause() instanceof UnsupportedOperationException uoe\n            && uoe.getMessage().contains(\"CteMutationStrategy\")) {\n        throw new ConfigurationError(\n            \"Drop hibernate.query.mutation_strategy=cte for this dialect\", e);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["hibernate-6","dialect","cte","configuration","startup-failure","bulk-update"],"backgroundTag":"dialect-capability-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}