hibernate/hibernate-orm · error · IllegalStateException
Session method called from entity lifecycle callback or Inte
Error message
Session method called from entity lifecycle callback or Interceptor method
What it means
While Hibernate invokes entity lifecycle callbacks (@PrePersist, @PostLoad, ...) and Interceptor methods it increments sessionUseProhibitedDepth; checkSessionReentrancy() then rejects any reentrant Session API call. JPA forbids EntityManager operations inside lifecycle listeners, and Hibernate enforces it to protect flush-cycle invariants — a session operation from inside a callback would recurse into the flush/persist machinery.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java:1135
if ( isClosed() ) {
if ( markForRollbackIfClosed && transactionCoordinator.isTransactionActive() ) {
markForRollbackOnly();
}
throw new IllegalStateException( "Session/EntityManager is closed" );
}
}
private void startSessionUseProhibited() {
sessionUseProhibitedDepth++;
}
private void finishSessionUseProhibited() {
sessionUseProhibitedDepth--;
}
protected void checkSessionReentrancy() {
if ( sessionUseProhibitedDepth > 0 ) {
throw new IllegalStateException( "Session method called from entity lifecycle callback or Interceptor method" );
}
}
protected void checksBeforeQueryCreation() {
checkOpen();
checkTransactionSyncStatus();
}
@Override
public void prepareForQueryExecution(boolean requiresTxn) {
checksBeforeQueryCreation();
if ( requiresTxn && !isTransactionInProgress() ) {
throw new TransactionRequiredException( "No active transaction" );
}
}
@Override
@NullableView on GitHub (pinned to fad1729dce)
Solutions
- Move queries and saves out of the callback into the service/repository method that coordinates the operation.
- Inside callbacks, only mutate the entity's own fields or use injected collaborators (CDI/Spring support bean injection into entity listeners) instead of the session.
- If cross-entity work is unavoidable, collect it in the listener and perform it after the flush completes (e.g., @PostPersist plus outer service step), or use a dedicated mechanism (Hibernate event system, Envers, domain events).
Example fix
// before
public class AuditListener {
@PrePersist
void prePersist(Auditable a) {
a.setCreatedBy(em.find(User.class, currentUserId())); // IllegalStateException
}
}
// after
public class AuditListener {
@PrePersist
void prePersist(Auditable a) {
a.setCreatedBy(currentUserProvider().username()); // no session use
}
}
// cross-entity work moves to the service after save() Defensive patterns
Strategy: fallback
Validate before calling
// Pattern: never touch the session in a callback; defer work out of it
public class DeferredWorkListener {
private final Queue<Runnable> pending = new ConcurrentLinkedQueue<>();
@PreUpdate
void onUpdate(Auditable a) {
a.setUpdatedAt(Instant.now()); // allowed: own fields only
pending.add(() -> counterService.touch(a.getClass())); // no session use here
}
public void runPending() { Runnable r; while ((r = pending.poll()) != null) r.run(); } // call after flush, outside callback
} Prevention
- Treat lifecycle callbacks and Interceptor methods as session-free zones by design
- Resolve lookups (current user, defaults) via injected beans or ThreadLocal context, not session queries
- Run cross-entity side effects after the flush in the service layer or via domain events
When it happens
Trigger: An entity listener or Interceptor callback calls session/em methods: em.persist/find/query inside @PrePersist/@PostLoad/@PreUpdate, session.flush() or session.get() inside Interceptor.onSave/onFlushDirty/onLoad; also user event listeners calling back into the same session during a flush cycle.
Common situations: Audit listeners resolving the current user with a query; denormalization/counter updates cascading from callbacks; code ported from Hibernate 5 native Session patterns where reentrancy went undetected; @PostLoad enriching entities from other tables.
Related errors
- Flush during cascade is dangerous
- Mapping for entity listener specified no callback methods: %
- Callback method annotated '@%s' in '%s' must return void and
- You can only annotate one callback method per callback type
- Class '<componentClassName>' is an '@Embeddable' type and ma
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/0649a10c011c0d2a.
Report an issue: GitHub.