hibernate/hibernate-orm · error · CannotContainSubGraphException

Attribute '{}' is not a to-many association

Error message

Attribute '{}' is not a to-many association

What it means

Before creating an element subgraph, checkToMany() requires the attribute to be a to-many association (ONE_TO_MANY or MANY_TO_MANY). Note that @ElementCollection attributes (PersistentAttributeType.ELEMENT_COLLECTION) are rejected too, even when their elements are managed types — only entity-to-entity collections pass.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java:226

	}

	@Override
	@Nonnull
	public SubGraphImplementor<K> addKeySubgraph() {
		throw new UnsupportedOperationException( "Not a Map-valued attribute node" );
	}

	protected void checkToOne() {
		final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType();
		if ( attributeType != MANY_TO_ONE && attributeType != ONE_TO_ONE && attributeType != EMBEDDED ) {
			throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-one association" );
		}
	}

	protected void checkToMany() {
		final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType();
		if ( attributeType != MANY_TO_MANY && attributeType != ONE_TO_MANY ) {
			throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-many association" );
		}
	}

	protected <T> ManagedDomainType<T> asManagedType(DomainType<T> domainType) {
		if ( domainType instanceof ManagedDomainType<T> managedDomainType ) {
			return managedDomainType;
		}
		else {
			throw new CannotContainSubGraphException( "Attribute '" + description()
					+ "' is of type '" + domainType.getTypeName()
					+ "' which is not a managed type" );
		}
	}

	private String description() {
		return attribute.getDeclaringType().getTypeName() + "." + attribute.getName();
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use addElementSubgraph() only on @OneToMany/@ManyToMany attributes
  2. For @ElementCollection, just add the attribute node (it fetches eagerly within the graph); if per-element subgraphs are truly needed, remap the part as @OneToMany to an entity
  3. For to-one attributes use addSingularSubgraph(); for basics no subgraph exists

Example fix

// before — element collection is not a to-many association
graph.addAttributeNode("tags")     // @ElementCollection
     .addElementSubgraph();         // → CannotContainSubGraphException

// after — the collection is fetched by being in the graph; remap to @OneToMany if you need element subgraphs
graph.addAttributeNode("tags");
Defensive patterns

Strategy: type-guard

Validate before calling

if (acceptsElementSubgraph(attr)) {
    node.addElementSubgraph().addAttributeNode("product");
}

Type guard

static boolean acceptsElementSubgraph(Attribute<?, ?> attr) {
    return switch (attr.getPersistentAttributeType()) {
        case ONE_TO_MANY, MANY_TO_MANY -> true;
        default -> false;   // note: ELEMENT_COLLECTION is rejected by Hibernate here
    };
}

Prevention

When it happens

Trigger: addElementSubgraph() on an attribute that is not ONE_TO_MANY/MANY_TO_MANY: a basic attribute, a @ManyToOne, or an @ElementCollection (element type basic or embeddable).

Common situations: Trying to fetch @ElementCollection contents through an element subgraph; generic graph builders applying element subgraphs everywhere; associations refactored between element collections and one-to-many sets.

Related errors


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