hibernate/hibernate-orm · error · IllegalArgumentException

Passed properties contained both a LOAD and a FETCH graph wh

Error message

Passed properties contained both a LOAD and a FETCH graph which is illegal - only one should be passed

What it means

EffectiveEntityGraph.applyConfiguredGraph() inspects a properties/hints map for the four graph hint keys (javax/jakarta persistence fetchgraph and loadgraph). A fetch graph and a load graph apply contradictory semantics to the same operation, so supplying both is rejected with IllegalArgumentException.

Source

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

	 *
	 * @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 );
			var loadHint = (RootGraphImplementor<?>) properties.get( HINT_JAVAEE_LOAD_GRAPH );
			if ( fetchHint == null ) {
				fetchHint = (RootGraphImplementor<?>) properties.get( HINT_SPEC_FETCH_GRAPH );
			}
			if ( loadHint == null ) {
				loadHint = (RootGraphImplementor<?>) properties.get( HINT_SPEC_LOAD_GRAPH );
			}

			if ( fetchHint != null ) {
				if ( loadHint != null ) {
					// can't have both
					throw new IllegalArgumentException(
							"Passed properties contained both a LOAD and a FETCH graph which is illegal - " +
							"only one should be passed"
					);
				}
				applyGraph( fetchHint, GraphSemantic.FETCH );
			}
			else if ( loadHint != null ) {
				applyGraph( loadHint, GraphSemantic.LOAD );
			}
		}
	}

	public void clear() {
		semantic = null;
		graph = null;
	}

	public void withAppliedGraph(GraphSemantic semantic, RootGraphImplementor<?> graph, Runnable action) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove one of the two hints so the map contains only a fetchgraph or only a loadgraph
  2. Sanitize merged hint maps before use: strip the unused key after merging
  3. Standardize on one spelling (jakarta.persistence.*) and audit shared hint maps for stray javax keys

Example fix

// before
Map<String, Object> hints = new HashMap<>();
hints.put("jakarta.persistence.fetchgraph", fetchGraph);
hints.put("jakarta.persistence.loadgraph", loadGraph); // both present -> IllegalArgumentException
em.find(Order.class, id, hints);

// after
Map<String, Object> hints = new HashMap<>();
hints.put("jakarta.persistence.fetchgraph", fetchGraph);
em.find(Order.class, id, hints);
Defensive patterns

Strategy: validation

Validate before calling

private static final Set<String> GRAPH_HINT_KEYS = Set.of(
    "jakarta.persistence.fetchgraph", "jakarta.persistence.loadgraph",
    "javax.persistence.fetchgraph", "javax.persistence.loadgraph");

static void assertSingleGraphHint(Map<String, Object> hints) {
    List<String> present = GRAPH_HINT_KEYS.stream()
        .filter(hints::containsKey).toList();
    if (present.size() > 1) {
        throw new IllegalArgumentException("Pass only one entity-graph hint, found: " + present);
    }
}

Try / catch

try {
    em.find(Order.class, id, hints);
} catch (IllegalArgumentException e) {
    if (String.valueOf(e.getMessage()).contains("both a LOAD and a FETCH graph")) {
        hints.remove("jakarta.persistence.loadgraph"); // keep fetchgraph only
        em.find(Order.class, id, hints);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Passing a properties map that contains both HINT_SPEC/JAVAEE_FETCH_GRAPH and HINT_SPEC/JAVAEE_LOAD_GRAPH (any mix of 'jakarta.persistence.fetchgraph', 'jakarta.persistence.loadgraph', 'javax.persistence.fetchgraph', 'javax.persistence.loadgraph') to an API that feeds applyConfiguredGraph(), such as EntityManager.find(cls, id, hints), session find-by-key operations, or Query hint processing.

Common situations: Hint maps assembled by merging defaults with per-call overrides (framework or utility code) without removing the losing key; javax-to-jakarta migration where both spellings get added; Spring Data JPA @EntityGraph combined with manually put graph hints; copy-pasting hint constants between call sites.

Related errors


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