hibernate/hibernate-orm · error · EntityActionVetoException
Action was vetoed: " + entityAction
Error message
Action was vetoed: " + entityAction
What it means
In the graph-based ActionQueue (default since Hibernate 8, hibernate.flush.queue.type=graph), early IDENTITY inserts are executed immediately inside addInsertAction (GraphBasedActionQueue.java:236). After execution it checks isVeto(): if a registered PreInsertEventListener returned true (veto), the queue throws EntityActionVetoException ("Action was vetoed: " + entityAction, EntityActionVetoException.java:32). The insert was skipped by a listener - typically a custom security/validation listener - and the queue surfaces the veto as an exception instead of silently dropping the row.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/GraphBasedActionQueue.java:236
executePendingInserts();
final var nonNullableTransientDeps = insert.findNonNullableTransientEntities();
if ( nonNullableTransientDeps != null ) {
flushCoordinator.getDecomposer().trackUnresolvedInsert( insert, nonNullableTransientDeps );
return;
}
ACTION_LOGGER.executingIdentityInsertImmediately();
insert.execute();
if ( !insert.isVeto() ) {
insert.makeEntityManaged();
executePendingInserts();
for ( var resolvedAction : flushCoordinator.getDecomposer().resolveDependentActions( insert.getInstance() ) ) {
addInsertAction( resolvedAction );
}
}
else {
throw new EntityActionVetoException( insert );
}
registerCleanupActions( insert );
}
private void addResolvedNonEarlyInsertAction(AbstractEntityInsertAction insert) {
ACTION_LOGGER.addingResolvedNonEarlyInsertAction();
if ( !insertions.contains( insert ) ) {
insertions.add( insert );
}
makeEntityManagedAndResolveDependentActions(insert);
}
private void makeEntityManagedAndResolveDependentActions(AbstractEntityInsertAction insert) {
if ( !insert.isVeto() ) {
insert.makeEntityManaged();
for ( var resolvedAction : flushCoordinator.getDecomposer().resolveDependentActions( insert.getInstance() ) ) {
addInsertAction( resolvedAction );
}View on GitHub (pinned to fad1729dce)
Solutions
- Inspect registered PreInsertEventListeners (Integrator / EventListenerRegistry) and fix the vetoing listener: return true only when the insert must actually be blocked, and log the reason
- If veto is the intended behavior, catch EntityActionVetoException in the use case and translate it into a domain response (e.g. 'rejected by policy')
- Verify the entity/condition match in the listener - veto firing for the wrong entity usually means an instanceof/null check bug in listener code
- As a diagnostic, temporarily set hibernate.flush.queue.type=legacy to confirm the same listener vetoes there too (it will drop the row rather than throw)
Example fix
// before - listener vetoes everything on any exception, inserts die at flush
public class AuditInsertListener implements PreInsertEventListener {
public boolean onPreInsert(PreInsertEvent event) {
try { check(event); return false; }
catch (Exception e) { return true; } // vetoes whole insert silently
}
}
// after - fail loudly instead of vetoing, veto only on explicit policy match
public boolean onPreInsert(PreInsertEvent event) {
if (isBlockedByPolicy(event)) { LOG.info("vetoing {}", event.getEntityName()); return true; }
check(event); // throws on real errors
return false;
} Defensive patterns
Strategy: try-catch
Try / catch
// treat a veto as a business rejection, not an infrastructure failure
try {
tx.begin(); em.persist(entity); tx.commit();
} catch (EntityActionVetoException e) {
// a PreInsertEventListener deliberately blocked this insert;
// surface 'rejected by policy' and audit which listener fired
throw new InsertRejectedException(entity, e.getMessage());
} Prevention
- Audit every registered PreInsertEventListener: true means 'block the insert', not 'event handled'
- Log the entity and reason whenever a listener returns true - silent vetoes look like data loss
- Scope veto listeners to specific entity types via the EventListenerRegistry instead of applying them globally
When it happens
Trigger: A registered org.hibernate.event.spi.PreInsertEventListener whose onPreInsert returns true for your entity (validation failure, permission check, feature flag), combined with an entity using GenerationType.IDENTITY so its insert takes the early/immediate path in the graph queue; enabling a listener at runtime or via @EntityListeners integration that votes veto.
Common situations: Custom compliance or tenant-permission listeners designed to block inserts of certain entities; test listeners that veto unexpectedly after refactoring; misconfigured listener returning true on error paths instead of throwing; misreading the veto contract (true = block, not 'handled').
Related errors
- Insert conflict 'do update' clause with constraint name is n
- The INSERT statement for table [%s] contains no column, and
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
- Insert conflict 'do update' clause with constraint name is n
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e1f8e88847a76703.
Report an issue: GitHub.