hibernate/hibernate-orm · error · UnsupportedOperationException
Decomposition not supported for %s
Error message
Decomposition not supported for %s
What it means
The graph-based flush planner Decomposer.decompose (Decomposer.java:315) translates queued actions into JDBC operations. It handles the known action types (entity insert/update/delete, collection recreate/remove/update, and QueuedOperationCollectionAction) and ends with `throw new UnsupportedOperationException("Decomposition not supported for " + executable.getClass().getName())` for anything else. Seeing it means an Executable action of an unrecognized type reached the graph planner - usually a custom action injected into the ActionQueue or a code path not yet covered by the new planner.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/Decomposer.java:315
cua,
ordinalBase,
session,
this,
operationConsumer
);
return;
}
if (executable instanceof QueuedOperationCollectionAction qoca) {
qoca.getPersister().decompose(
qoca,
ordinalBase,
session,
operationConsumer
);
return;
}
throw new UnsupportedOperationException( "Decomposition not supported for " + executable.getClass().getName() );
}
/// Track an insert action that has unresolved dependencies on transient entities.
/// This is called for IDENTITY inserts that have transient FK dependencies and need
/// to be deferred until those dependencies are satisfied.
///
/// @param insert the insert action with unresolved dependencies
/// @param dependencies the non-nullable transient dependencies
public void trackUnresolvedInsert(AbstractEntityInsertAction insert, NonNullableTransientDependencies dependencies) {
if ( ACTION_LOGGER.isTraceEnabled() ) {
ACTION_LOGGER.tracef( "Tracking unresolved insert for %s", insert.getEntityName() );
for (Object transientEntity : dependencies.getNonNullableTransientEntities()) {
ACTION_LOGGER.tracef(
" - depends on: %s@%s",
transientEntity.getClass().getSimpleName(),
System.identityHashCode(transientEntity)
);
}View on GitHub (pinned to fad1729dce)
Solutions
- Check the class name printed in the message - if it is your own or a third-party Executable, remove/replace that mechanism (e.g. convert it to an event listener or a post-flush hook)
- As a workaround/fallback, set hibernate.flush.queue.type=legacy (see FlushSettings.FLUSH_QUEUE_TYPE) to use the traditional ActionQueue that executes actions directly
- If the class is a built-in Hibernate action, report it upstream - the decomposer's type coverage has a gap
- Audit Integrators/custom SPI code that touches session.getActionQueue() internals
Example fix
# before - graph queue (8.x default) cannot decompose a custom Executable # application.properties has no queue setting, custom action hits Decomposer.decompose # after - pin the legacy queue until the extension is updated hibernate.flush.queue.type=legacy
Defensive patterns
Strategy: fallback
Try / catch
try {
session.flush();
} catch (UnsupportedOperationException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Decomposition not supported")) {
// custom/unsupported Executable reached the graph planner:
// fall back to the legacy queue for this deployment and report the class name
log.error("Graph decomposer cannot handle: {}", e.getMessage());
throw new ConfigurationException(
"Set hibernate.flush.queue.type=legacy or remove the custom action", e);
}
throw e;
} Prevention
- Never inject custom Executable actions into the ActionQueue; use event listeners or flush/commit callbacks instead
- When upgrading to Hibernate 8, test flush-heavy paths against the graph queue (now default) in CI
- Know the escape hatch: hibernate.flush.queue.type=legacy restores the traditional queue
When it happens
Trigger: Custom code adding its own org.hibernate.action.spi.Executable implementations to the ActionQueue; third-party Hibernate extensions that queue exotic action types during flush; running with hibernate.flush.queue.type=graph (the 8.x default) after upgrading, hitting an action class the decomposer does not recognize.
Common situations: Upgrading to Hibernate 8 where the graph queue became the default and an extension's custom action is no longer supported; frameworks built on internal ActionQueue APIs; custom replication/cache synchronization actions registered during flush.
Related errors
- Instance of '%s' references an unsaved transient instance of
- Audit graph mutation plan used with non-graph action queue
- Audit graph mutation plan used with non-graph action queue
- cannot recreate collection while filter is enabled [%s : %s]
- null key for collection: %s
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f698b8578be1d0be.
Report an issue: GitHub.