hibernate/hibernate-orm · error · IllegalStateException

Cannot overwrite existing state, should clear previous state

Error message

Cannot overwrite existing state, should clear previous state first

What it means

EffectiveEntityGraph holds the entity graph currently applied to a session's load plans. applyGraph(graph, semantic) calls verifyWriteability(), which refuses to install a second graph while a semantic is already set and the instance was created with allowOverwrite=false (the default constructor used by LoadQueryInfluencers). The IllegalStateException prevents two conflicting fetch strategies from being silently stacked on one session.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java:96

	 * may be null, but that should generally be considered mis-use.
	 *
	 * @throws IllegalArgumentException Thrown if the semantic is null
	 * @throws IllegalStateException If previous state is still available (hasn't been cleared).
	 */
	public void applyGraph(RootGraphImplementor<?> graph, GraphSemantic semantic) {
		if ( semantic == null ) {
			throw new IllegalArgumentException( "Graph semantic cannot be null" );
		}
		verifyWriteability();
		LOG.tracef( "Setting effective graph state [%s] : %s", semantic.name(), graph );
		this.semantic = semantic;
		this.graph = graph;
	}

	private void verifyWriteability() {
		if ( ! allowOverwrite ) {
			if ( semantic != null ) {
				throw new IllegalStateException( "Cannot overwrite existing state, should clear previous state first" );
			}
		}
	}

	/**
	 * Apply a graph and semantic based on configuration properties or hints
	 * based on {@link GraphSemantic#getJakartaHintName()} for {@link GraphSemantic#LOAD} or
	 * {@link GraphSemantic#FETCH}.
	 * <p>
	 * The semantic is required.  The graph
	 * may be null, but that should generally be considered mis-use.
	 *
	 * @throws IllegalArgumentException If both kinds of graphs were present in the properties/hints
	 * @throws IllegalStateException If previous state is still available (hasn't been cleared).
	 */
	public void applyConfiguredGraph(@Nullable Map<String,?> properties) {
		if ( properties != null && !properties.isEmpty() ) {
			var fetchHint = (RootGraphImplementor<?>) properties.get( HINT_JAVAEE_FETCH_GRAPH );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call effectiveEntityGraph.clear() (or verify and clear first) before applying the new graph
  2. Prefer per-operation graphs (find()/query hints jakarta.persistence.fetchgraph/loadgraph, or query.applyGraph) which Hibernate resets automatically
  3. If intentional re-application is needed, construct/use an EffectiveEntityGraph with allowOverwrite=true rather than fighting the guard

Example fix

// before
var eg = ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph();
eg.applyGraph(orderGraph, GraphSemantic.FETCH);
eg.applyGraph(userGraph, GraphSemantic.FETCH); // IllegalStateException

// after
var eg = ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph();
eg.clear();
eg.applyGraph(userGraph, GraphSemantic.FETCH);
Defensive patterns

Strategy: validation

Validate before calling

var eg = ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph();
eg.clear(); // no-op when nothing is applied
eg.applyGraph(graph, GraphSemantic.FETCH);

Try / catch

try {
    eg.applyGraph(graph, semantic);
} catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().contains("Cannot overwrite existing state")) {
        eg.clear();
        eg.applyGraph(graph, semantic); // retry once after clearing
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling applyGraph() twice on the session's effective entity graph without an intervening clear(): e.g. ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph().applyGraph(g, semantic) followed by another applyGraph, or LoadQueryInfluencers.applyEntityGraph(rootGraph, semantic) while a previous graph is still in effect. Per-operation APIs such as em.find(...) with hints or merge(object, loadGraph) clear the graph themselves, so this fires on the manual/session-level path.

Common situations: Reusing one long-lived Session/EntityManager and applying a different session-level entity graph per request without clearing; internal re-application of an initial graph after a temporary FETCH graph (follow-on locking) when the graph was never cleared; code migrated from per-query hints to session-level graphs.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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