hibernate/hibernate-orm · error · HibernateException
Unable to perform beforeTransactionCompletion callback: {}
Error message
Unable to perform beforeTransactionCompletion callback: {} What it means
Before a transaction completes, Hibernate drains BeforeTransactionCompletionProcessQueue and runs each BeforeCompletionCallback (flush-time pre-commit hooks, e.g. from interceptors, event listeners, or cache pre-invalidation). HibernateException rethrows as-is; any other exception is wrapped in HibernateException with this message. Unlike the after-completion variant, this fires during pre-commit processing, so the transaction will not commit - expect a rollback.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java:31
*/
class BeforeTransactionCompletionProcessQueue
extends AbstractTransactionCompletionProcessQueue<BeforeCompletionCallback> {
BeforeTransactionCompletionProcessQueue(SharedSessionContractImplementor session) {
super( session );
}
void beforeTransactionCompletion() {
BeforeCompletionCallback process;
while ( (process = processes.poll()) != null ) {
try {
process.doBeforeTransactionCompletion( session );
}
catch (HibernateException he) {
throw he;
}
catch (Exception e) {
throw new HibernateException(
"Unable to perform beforeTransactionCompletion callback: " + e.getMessage(), e );
}
}
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Read the nested cause to find the failing callback and fix it directly - the wrapper only hides its message otherwise.
- Make Interceptor.beforeTransactionCompletion implementations exception-safe: catch and log anything that must not block commit.
- Move logic that may legitimately fail (external calls) out of pre-commit hooks into post-commit or business code.
- Re-run with trace logging on org.hibernate.engine.internal to see which queued process was executing when it threw.
Example fix
// before
@Override
public void beforeTransactionCompletion(Transaction tx) {
auditWriter.write(currentAuditRecord()); // IO exception aborts commit
}
// after
@Override
public void beforeTransactionCompletion(Transaction tx) {
try { auditWriter.write(currentAuditRecord()); }
catch (IOException e) { log.error("audit pre-write failed", e); }
} Defensive patterns
Strategy: try-catch
Try / catch
try {
tx.commit();
} catch (HibernateException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Unable to perform beforeTransactionCompletion callback")) {
// commit did NOT happen; inspect e.getCause() for the failing listener/interceptor
log.error("pre-commit callback failed, rolling back", e.getCause());
}
throw e;
} Prevention
- Keep Interceptor.beforeTransactionCompletion free of fallible IO; wrap its body in try/catch.
- Unit-test interceptors and event listeners against the commit path, not just the CRUD path.
- Enable trace logging for org.hibernate.engine.internal when diagnosing which queued callback threw.
When it happens
Trigger: A registered beforeTransactionCompletion callback throwing a non-Hibernate exception: custom Interceptor.beforeTransactionCompletion, Bean Validation or Envers hooks, entity listeners, timestamp/cache pre-processes. Thrown from beforeTransactionCompletion() during commit, failing the commit.
Common situations: Interceptors doing pre-commit validation or audit stamps that hit NPEs/IO errors; version conflicts in custom locking code; listeners assuming state that a rollback path does not provide; errors surfacing only under JTA where beforeCompletion runs on the synchronizer thread.
Related errors
- Unable to perform afterTransactionCompletion callback: {}
- Transaction timeout expired
- Flush during cascade is dangerous
- cannot recreate collection while filter is enabled: " + coll
- Newer version [" + latestVersion + "] of entity [" + infoStr
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/ac516581918133d6.
Report an issue: GitHub.