hibernate/hibernate-orm · error · HibernateException

Audit graph mutation plan used with non-graph action queue

Error message

Audit graph mutation plan used with non-graph action queue

What it means

AuditEntityMutationPlanContributor builds the plan for auditing/temporal-tracking entity changes and, like its collection sibling, resolves its collector by casting the session's ActionQueue to GraphBasedActionQueue (AuditEntityMutationPlanContributor.java:124). When the session runs the legacy queue, the instanceof check fails and it throws HibernateException("Audit graph mutation plan used with non-graph action queue"). The entity-audit machinery is enabled but the flush implementation it depends on has been switched off.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/entity/AuditEntityMutationPlanContributor.java:124

						state,
						modificationType,
						entityAuditSupport
				)
		);
	}

	private EntityKey resolveEntityKey(
			Object identifier,
			SharedSessionContractImplementor session) {
		return session.generateEntityKey( identifier, entityPersister );
	}

	private GraphBasedActionQueue resolveCollector(SessionImplementor session) {
		final var actionQueue = session.getActionQueue();
		if ( actionQueue instanceof GraphBasedActionQueue graphBasedActionQueue ) {
			return graphBasedActionQueue;
		}
		throw new HibernateException( "Audit graph mutation plan used with non-graph action queue" );
	}

	private boolean shouldAuditUpdate(int[] dirtyAttributeIndexes, boolean hasDirtyCollection) {
		if ( dirtyAttributeIndexes == null || dirtyAttributeIndexes.length == 0 ) {
			return true;
		}
		if ( hasDirtyCollection ) {
			return true;
		}
		for ( int dirtyIndex : dirtyAttributeIndexes ) {
			if ( auditedPropertyMask[dirtyIndex] ) {
				return true;
			}
		}
		return false;
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set hibernate.flush.queue.type=graph (or simply remove the property - graph is the default) so the audit plan gets its GraphBasedActionQueue
  2. Search every property source (persistence.xml, application.yaml, env vars, system properties, programmatic settings) for hibernate.flush.queue.type and remove legacy overrides
  3. Rebuild/restart the SessionFactory after fixing settings - existing sessions keep their old queue type
  4. If legacy must stay, disable the audit entity mutation plan contributor until it supports the legacy queue

Example fix

// before - legacy queue forced at bootstrap while audit plans are registered
Map<String,Object> props = Map.of("hibernate.flush.queue.type", "legacy");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("auditPu", props);

// after - use the graph queue required by the audit plan
Map<String,Object> props = Map.of("hibernate.flush.queue.type", "graph");
Defensive patterns

Strategy: validation

Validate before calling

// assert queue/audit alignment before opening sessions
if (auditEnabled && !"graph".equals(settings.get("hibernate.flush.queue.type"))) {
    throw new ConfigurationException(
        "Audit entity plans need GraphBasedActionQueue; set hibernate.flush.queue.type=graph");
}

Prevention

When it happens

Trigger: Audit/temporal entity plans active in the sameSessionFactory where hibernate.flush.queue.type=legacy is configured; sessions opened from a factory built before the graph setting was corrected; property sources (env var, system property) overriding the queue type back to legacy in one environment.

Common situations: Post-8.x upgrades that pinned 'legacy' to avoid other regressions, then turned on the audit feature; staging configs diverging from production; programmatic bootstrap (SessionFactoryBuilder) forgetting to clear the legacy flag.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/505a97773d6810da. Report an issue: GitHub.