{"record":{"id":"1b1f5ca91ff4ab55","repo":"hibernate/hibernate-orm","slug":"there-are-delayed-insert-actions-before-operation","errorCode":null,"errorMessage":"There are delayed insert actions before operation as cascade level 0.","messagePattern":"There are delayed insert actions before operation as cascade level 0\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java","lineNumber":588,"sourceCode":"\t\t// todo : should this get moved to PersistentContext?\n\t\t// logically, is PersistentContext the \"thing\" to which an interceptor gets attached?\n\t\tfinal Object result = persistenceContext.getEntity( key );\n\t\tif ( result == null ) {\n\t\t\tfinal Object newObject = callInterceptorCallback(\n\t\t\t\t\t() -> getInterceptor().getEntity( key.getEntityName(), key.getIdentifier() ) );\n\t\t\tif ( newObject != null ) {\n\t\t\t\tlock( newObject, LockMode.NONE );\n\t\t\t}\n\t\t\treturn newObject;\n\t\t}\n\t\telse {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tprotected void checkNoUnresolvedActionsBeforeOperation() {\n\t\tif ( persistenceContext.getCascadeLevel() == 0 && actionQueue.hasUnresolvedEntityInsertActions() ) {\n\t\t\tthrow new IllegalStateException( \"There are delayed insert actions before operation as cascade level 0.\" );\n\t\t}\n\t}\n\n\tprotected void checkNoUnresolvedActionsAfterOperation() {\n\t\tif ( persistenceContext.getCascadeLevel() == 0 ) {\n\t\t\tactionQueue.checkNoUnresolvedActionsAfterOperation();\n\t\t}\n\t\tdelayedAfterCompletion();\n\t}\n\n\t@Override\n\tpublic void delayedAfterCompletion() {\n\t\tsuper.delayedAfterCompletion();\n\t}\n\n\t@Override\n\tpublic void pulseTransactionCoordinator() {\n\t\tsuper.pulseTransactionCoordinator();","sourceCodeStart":570,"sourceCodeEnd":606,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java#L570-L606","documentation":"With identity-style immediate inserts (IDENTITY generation, or inserts queued via ActionQueue), Hibernate can end a unit of work with 'unresolved entity insert actions' — inserts held back because they participate in circular FK dependencies. Operations such as lock() call checkNoUnresolvedActionsBeforeOperation(), which refuses to run while such actions are pending at cascade level 0, throwing IllegalStateException. This guards against executing an operation whose outcome could depend on un-flushed insert state.","triggerScenarios":"Persisting entities with IDENTITY identifiers involved in bidirectional FK cycles, then calling session.lock/refresh/get-style guarded operations before a flush resolves the queue. Triggered when persistenceContext.getCascadeLevel() == 0 and actionQueue.hasUnresolvedEntityInsertActions().","commonSituations":"Parent/child mutual references with IDENTITY keys on MySQL/SQL Server (no sequences); circular foreign keys between two new entities; legacy schemas forcing IDENTITY; operations triggered lazily (lazy loading forcing the check) right after saving such a graph.","solutions":["Flush first: session.flush() resolves the pending insert actions before the guarded operation","Switch identifier generation to SEQUENCE (or pooled/table) so inserts are not forced through the unresolved-action queue","Break the FK cycle: make one side nullable and set the association after both saves, or use join-table mapping","Reorder the code so lock/refresh happens before persisting the circular graph"],"exampleFix":"// before (Order.id is IDENTITY, Order.customer <-> Customer.orders circular FK)\nsession.persist(order);\nsession.lock(customer, LockMode.NONE); // IllegalStateException: delayed insert actions\n\n// after\nsession.persist(order);\nsession.flush();            // resolve delayed insert actions first\nsession.lock(customer, LockMode.NONE);","handlingStrategy":"try-catch","validationCode":"// Flush resolves pending identity inserts before guarded operations\nif (!session.getActionQueue().hasUnresolvedEntityInsertActions()) {\n    session.lock(entity, LockMode.NONE);\n} else {\n    session.flush();\n    session.lock(entity, LockMode.NONE);\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.lock(entity, LockMode.NONE);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"delayed insert actions\")) {\n        session.flush();                       // resolve the delayed inserts\n        session.lock(entity, LockMode.NONE);   // retry once\n    } else {\n        throw e;\n    }\n}","preventionTips":["Prefer SEQUENCE identifier generation over IDENTITY to avoid unresolved-insert queues entirely","Avoid circular FK references between newly created entities; set one side after both are persisted","Flush after persisting graphs with IDENTITY keys before performing lock/refresh operations"],"tags":["hibernate","action-queue","identity-generation","cascade","flush","insert-ordering"],"backgroundTag":"pending-insert-actions","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}