{"record":{"id":"f698b8578be1d0be","repo":"hibernate/hibernate-orm","slug":"decomposition-not-supported-for-s","errorCode":null,"errorMessage":"Decomposition not supported for %s","messagePattern":"Decomposition not supported for (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/Decomposer.java","lineNumber":315,"sourceCode":"\t\t\t\t\tcua,\n\t\t\t\t\tordinalBase,\n\t\t\t\t\tsession,\n\t\t\t\t\tthis,\n\t\t\t\t\toperationConsumer\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (executable instanceof QueuedOperationCollectionAction qoca) {\n\t\t\tqoca.getPersister().decompose(\n\t\t\t\t\tqoca,\n\t\t\t\t\tordinalBase,\n\t\t\t\t\tsession,\n\t\t\t\t\toperationConsumer\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tthrow new UnsupportedOperationException( \"Decomposition not supported for \" +  executable.getClass().getName() );\n\t}\n\n\t/// Track an insert action that has unresolved dependencies on transient entities.\n\t/// This is called for IDENTITY inserts that have transient FK dependencies and need\n\t/// to be deferred until those dependencies are satisfied.\n\t///\n\t/// @param insert the insert action with unresolved dependencies\n\t/// @param dependencies the non-nullable transient dependencies\n\tpublic void trackUnresolvedInsert(AbstractEntityInsertAction insert, NonNullableTransientDependencies dependencies) {\n\t\tif ( ACTION_LOGGER.isTraceEnabled() ) {\n\t\t\tACTION_LOGGER.tracef( \"Tracking unresolved insert for %s\", insert.getEntityName() );\n\t\t\tfor (Object transientEntity : dependencies.getNonNullableTransientEntities()) {\n\t\t\t\tACTION_LOGGER.tracef(\n\t\t\t\t\t\t\"  - depends on: %s@%s\",\n\t\t\t\t\t\ttransientEntity.getClass().getSimpleName(),\n\t\t\t\t\t\tSystem.identityHashCode(transientEntity)\n\t\t\t\t);\n\t\t\t}","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/Decomposer.java#L297-L333","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before - graph queue (8.x default) cannot decompose a custom Executable\n# application.properties has no queue setting, custom action hits Decomposer.decompose\n\n# after - pin the legacy queue until the extension is updated\nhibernate.flush.queue.type=legacy","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    session.flush();\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Decomposition not supported\")) {\n        // custom/unsupported Executable reached the graph planner:\n        // fall back to the legacy queue for this deployment and report the class name\n        log.error(\"Graph decomposer cannot handle: {}\", e.getMessage());\n        throw new ConfigurationException(\n            \"Set hibernate.flush.queue.type=legacy or remove the custom action\", e);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["flush","graph-queue","unsupported-operation","extension","migration","hibernate"],"backgroundTag":"unsupported-flush-action-type","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}