{"record":{"id":"db894aa2a4e7213b","repo":"hibernate/hibernate-orm","slug":"cannot-overwrite-existing-state-should-clear-prev","errorCode":null,"errorMessage":"Cannot overwrite existing state, should clear previous state first","messagePattern":"Cannot overwrite existing state, should clear previous state first","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java","lineNumber":96,"sourceCode":"\t * may be null, but that should generally be considered mis-use.\n\t *\n\t * @throws IllegalArgumentException Thrown if the semantic is null\n\t * @throws IllegalStateException If previous state is still available (hasn't been cleared).\n\t */\n\tpublic void applyGraph(RootGraphImplementor<?> graph, GraphSemantic semantic) {\n\t\tif ( semantic == null ) {\n\t\t\tthrow new IllegalArgumentException( \"Graph semantic cannot be null\" );\n\t\t}\n\t\tverifyWriteability();\n\t\tLOG.tracef( \"Setting effective graph state [%s] : %s\", semantic.name(), graph );\n\t\tthis.semantic = semantic;\n\t\tthis.graph = graph;\n\t}\n\n\tprivate void verifyWriteability() {\n\t\tif ( ! allowOverwrite ) {\n\t\t\tif ( semantic != null ) {\n\t\t\t\tthrow new IllegalStateException( \"Cannot overwrite existing state, should clear previous state first\" );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Apply a graph and semantic based on configuration properties or hints\n\t * based on {@link GraphSemantic#getJakartaHintName()} for {@link GraphSemantic#LOAD} or\n\t * {@link GraphSemantic#FETCH}.\n\t * <p>\n\t * The semantic is required.  The graph\n\t * may be null, but that should generally be considered mis-use.\n\t *\n\t * @throws IllegalArgumentException If both kinds of graphs were present in the properties/hints\n\t * @throws IllegalStateException If previous state is still available (hasn't been cleared).\n\t */\n\tpublic void applyConfiguredGraph(@Nullable Map<String,?> properties) {\n\t\tif ( properties != null && !properties.isEmpty() ) {\n\t\t\tvar fetchHint = (RootGraphImplementor<?>) properties.get( HINT_JAVAEE_FETCH_GRAPH );","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java#L78-L114","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call effectiveEntityGraph.clear() (or verify and clear first) before applying the new graph","Prefer per-operation graphs (find()/query hints jakarta.persistence.fetchgraph/loadgraph, or query.applyGraph) which Hibernate resets automatically","If intentional re-application is needed, construct/use an EffectiveEntityGraph with allowOverwrite=true rather than fighting the guard"],"exampleFix":"// before\nvar eg = ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph();\neg.applyGraph(orderGraph, GraphSemantic.FETCH);\neg.applyGraph(userGraph, GraphSemantic.FETCH); // IllegalStateException\n\n// after\nvar eg = ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph();\neg.clear();\neg.applyGraph(userGraph, GraphSemantic.FETCH);","handlingStrategy":"validation","validationCode":"var eg = ((SessionImplementor) session).getLoadQueryInfluencers().getEffectiveEntityGraph();\neg.clear(); // no-op when nothing is applied\neg.applyGraph(graph, GraphSemantic.FETCH);","typeGuard":null,"tryCatchPattern":"try {\n    eg.applyGraph(graph, semantic);\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Cannot overwrite existing state\")) {\n        eg.clear();\n        eg.applyGraph(graph, semantic); // retry once after clearing\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always pair session-level applyGraph with clear() when the operation ends (try/finally)","Prefer per-query graphs (hints, query.applyGraph) over session-level effective-graph state","Never assume the effective graph is empty in a shared/long-lived session — clear before applying"],"tags":["hibernate","entity-graph","session-state","illegalstate","fetch-strategy"],"backgroundTag":"invalid-state-transition","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}