hibernate/hibernate-orm · error · IllegalStateException
Dialect returns null TemporaryTableStrategy for temporary ta
Error message
Dialect returns null TemporaryTableStrategy for temporary table {} of type {} What it means
Hibernate uses temporary tables to execute multi-table bulk HQL (UPDATE/DELETE on JOINED-inheritance or secondary-table entities). StandardTemporaryTableExporter.getDefaultTemporaryTableStrategy maps the TemporaryTable's kind (LOCAL/GLOBAL/PERSISTENT) to dialect.getLocalTemporaryTableStrategy()/getGlobalTemporaryTableStrategy()/getPersistentTemporaryTableStrategy(). Since Hibernate 7.1 the base Dialect returns a non-null strategy only for getSupportedTemporaryTableKind() and null for the other kinds (Dialect.java:3996-4010), so asking for a kind the dialect does not support throws IllegalStateException('Dialect returns null TemporaryTableStrategy ...') the first time temp-table SQL (create/drop/truncate) is generated.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/temptable/StandardTemporaryTableExporter.java:67
}
@Deprecated(forRemoval = true, since = "7.1")
protected String getTruncateTableCommand() {
return dialect.getTemporaryTableTruncateCommand();
}
protected String getTruncateTableCommand(TemporaryTableStrategy temporaryTableStrategy) {
return temporaryTableStrategy.getTemporaryTableTruncateCommand();
}
private TemporaryTableStrategy getDefaultTemporaryTableStrategy(TemporaryTable temporaryTable) {
final TemporaryTableStrategy temporaryTableStrategy = switch ( temporaryTable.getTemporaryTableKind() ) {
case LOCAL -> dialect.getLocalTemporaryTableStrategy();
case GLOBAL -> dialect.getGlobalTemporaryTableStrategy();
case PERSISTENT -> dialect.getPersistentTemporaryTableStrategy();
};
if ( temporaryTableStrategy == null ) {
throw new IllegalStateException(
"Dialect returns null TemporaryTableStrategy for temporary table " + temporaryTable.getQualifiedTableName() + " of type " + temporaryTable.getTemporaryTableKind() );
}
return temporaryTableStrategy;
}
@Override
public String getSqlCreateCommand(TemporaryTable temporaryTable) {
final TemporaryTableStrategy temporaryTableStrategy = getDefaultTemporaryTableStrategy( temporaryTable );
final var buffer = new StringBuilder( getCreateCommand( temporaryTableStrategy ) ).append( ' ' );
buffer.append( temporaryTable.getQualifiedTableName() );
buffer.append( '(' );
for ( TemporaryTableColumn column : temporaryTable.getColumnsForExport() ) {
buffer.append( column.getColumnName() ).append( ' ' );
final int sqlTypeCode = column.getJdbcMapping().getJdbcType().getDdlTypeCode();
final String databaseTypeName = column.getSqlTypeDefinition();
buffer.append( databaseTypeName );View on GitHub (pinned to fad1729dce)
Solutions
- Remove the explicit temporary-table mutation-strategy setting and let Hibernate choose the dialect-appropriate default
- Match the strategy to the dialect: local_temporary_table only on LOCAL dialects (MySQL, HSQLDB, Transact-SQL family), global_temporary_table only on GLOBAL dialects (H2, Oracle, HANA, DB2)
- In a custom dialect, override getLocalTemporaryTableStrategy()/getGlobalTemporaryTableStrategy() to return a real TemporaryTableStrategy (StandardLocalTemporaryTableStrategy/StandardGlobalTemporaryTableStrategy) instead of the null default
- If the mismatch cannot be fixed by config, execute the bulk operation via native SQL
Example fix
// before: GLOBAL temp-table strategy forced on a LOCAL-only dialect
Map<String,Object> cfg = new HashMap<>();
cfg.put("hibernate.query.mutation_strategy", "global_temporary_table"); // -> IllegalStateException on MySQL
// after: let the dialect pick
// (remove the property entirely; Dialect default is used) Defensive patterns
Strategy: validation
Validate before calling
// At startup, assert the configured bulk-id strategy is actually usable on this dialect
static void assertTemporaryTableStrategyConsistent(Dialect dialect, TemporaryTableKind configuredKind) {
TemporaryTableStrategy strategy = switch (configuredKind) {
case LOCAL -> dialect.getLocalTemporaryTableStrategy();
case GLOBAL -> dialect.getGlobalTemporaryTableStrategy();
case PERSISTENT -> dialect.getPersistentTemporaryTableStrategy();
};
if (strategy == null) {
throw new IllegalStateException(dialect + " has no " + configuredKind
+ " temporary table strategy; remove the mutation-strategy override or fix the dialect");
}
} Try / catch
try {
em.createQuery("delete from JoinedRoot e where e.flag = :f").executeUpdate();
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Dialect returns null TemporaryTableStrategy")) {
// config mismatch: fall back to per-row operations or native bulk SQL for this dialect
throw new ConfigurationException("Remove the temporary-table mutation strategy override for this dialect", e);
}
throw e;
} Prevention
- Do not copy hibernate.query.mutation_strategy settings between projects on different databases
- If you subclass Dialect, never return null from the temporary-table strategy getters -- return a Standard*TemporaryTableStrategy
- Exercise one bulk UPDATE/DELETE on a JOINED entity in a startup/CI test per supported dialect
When it happens
Trigger: Configuring an SQM mutation strategy whose temp-table kind is unsupported by the dialect -- e.g. enabling the global-temporary-table bulk-id strategy on a LOCAL-only dialect (MySQL, HSQLDB, SQL Server/Sybase) or the local-temporary strategy on a GLOBAL dialect (H2, Oracle, HANA, DB2) -- and then executing a bulk UPDATE/DELETE against a JOINED entity. Also caused by a custom Dialect overriding getSupportedTemporaryTableKind()/the strategy getters inconsistently (returning null).
Common situations: Copying hibernate.query.mutation_strategy / bulk-id settings between projects running different databases; performance tuning that pins the temporary-table strategy without checking dialect support; upgrading to Hibernate 7.1 where these strategy getters became nullable; custom dialect subclasses that return null.
Related errors
- Unable to resolve name [{}] as strategy [{}]
- Default resolver threw exception
- Could not instantiate named dialect class [%s]
- Unable to construct requested dialect [<dialectReference>]
- Unable to determine Dialect without JDBC metadata (please se
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/80b47dd747a5ac12.
Report an issue: GitHub.