hibernate/hibernate-orm · error · IllegalStateException

Unsupported JdbcOperation type: %s

Error message

Unsupported JdbcOperation type: %s

What it means

Thrown during flush by the graph-based ActionQueue's step executor when a queued FlushOperation's JdbcOperation is neither a PreparableMutationOperation (normal prepared SQL mutation) nor a SelfExecutingUpdateOperation (mutation that executes itself, e.g. soft-delete handling). It is an internal dispatch invariant: the executor only knows how to run those two shapes, so any other JdbcOperation implementation is rejected. In practice the class name in the message points to a custom/third-party mutation operation or an internal Hibernate bug, not to an entity mapping mistake.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/exec/AbstractStepExecutor.java:98

			final boolean execute = beforeOperationExecution( flushOperation );

			// No-op operations: only carry post-execution callback, skip SQL execution
			if ( flushOperation.getKind() != MutationKind.NO_OP && execute ) {
				final var bindPlan = flushOperation.getBindPlan();
				if ( bindPlan.getGeneratedValuesCollector() != null ) {
					// we need to execute these without batching
					executeWithGeneratedValues( flushOperation );
				}
				else {
					final var jdbcOperation = flushOperation.getJdbcOperation();
					if ( jdbcOperation instanceof PreparableMutationOperation preparable ) {
						executePreparable( preparable, flushOperation );
					}
					else if ( jdbcOperation instanceof SelfExecutingUpdateOperation selfExecuting ) {
						executeSelfExecuting( selfExecuting, flushOperation );
					}
					else {
						throw new IllegalStateException(
								"Unsupported JdbcOperation type: " + jdbcOperation.getClass().getName() );
					}
				}
			}

			afterOperationExecution( flushOperation, newlyManagedEntityConsumer, fixupOperationConsumer );
		}
	}

	protected boolean beforeOperationExecution(FlushOperation flushOperation) {
		final var preExecutionCallback = flushOperation.getPreExecutionCallback();
		if ( preExecutionCallback == null ) {
			return true;
		}
		final boolean execute = preExecutionCallback.beforeExecution( (SessionImplementor) session );
		flushOperation.setExecutionSkipped( !execute );
		return execute;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Inspect the class name in the message - it names the exact rejected JdbcOperation implementation; identify which library produces it and remove or upgrade that integration.
  2. If the operation comes from an extension that only supports the legacy ordering, set hibernate.flush.queue.type=legacy as a workaround (valid values are 'graph' and 'legacy').
  3. If you implement MutationOperation yourself, make getJdbcOperation() return a PreparableMutationOperation or a SelfExecutingUpdateOperation.
  4. If no custom code is involved, capture the failing flush in a minimal test and report it against the Hibernate action-queue component.

Example fix

// before
<persistence-unit>
  <properties>
    <property name="hibernate.flush.queue.type" value="graph"/>
  </properties>
</persistence-unit>
// after - fall back to the legacy action queue while the integration is fixed
<persistence-unit>
  <properties>
    <property name="hibernate.flush.queue.type" value="legacy"/>
  </properties>
</persistence-unit>
Defensive patterns

Strategy: try-catch

Try / catch

try {
    session.flush();
}
catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unsupported JdbcOperation type")) {
        // identify the integration named in the message, roll back, switch queue type or remove it
        tx.rollback();
    }
    throw e;
}

Prevention

When it happens

Trigger: session.flush() or transaction commit runs a FlushOperation whose getJdbcOperation() returns a custom JdbcOperation implementation; typically produced by an integration that generates its own mutation operations, or an extension compiled against a different Hibernate version where the operation SPI differed.

Common situations: Custom OGM-like drivers or audit/history extensions supplying their own MutationOperation; upgrading to the 8.0 graph-based flush queue while an extension only supports the legacy queue; misrouted soft-delete/custom-SQL strategies.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/61b153e1425e51f5. Report an issue: GitHub.