hibernate/hibernate-orm · error · IllegalArgumentException

Only embeddables without collections are supported!

Error message

Only embeddables without collections are supported!

What it means

When a dynamic instantiation / tuple selection (select new, criteria tuple/array) is reused as an embeddable-valued model part, Hibernate builds an AnonymousTupleEmbeddableValuedModelPart by iterating the embeddable's attributes. Each attribute must be a SingularPersistentAttribute — anonymous tuple model parts only support embeddables made of singular (basic/embeddable/entity) attributes. Any plural attribute (@OneToMany, @ManyToMany, @ElementCollection) inside the embeddable fails with IllegalArgumentException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tuple/internal/AnonymousTupleEmbeddableValuedModelPart.java:123

		this.domainType = domainType;
		this.componentName = componentName;
		this.existingModelPartContainer = existingModelPartContainer;
		this.fetchableIndex = fetchableIndex;
	}

	private Map<String, ModelPart> createModelParts(
			SqmExpressible<?> sqmExpressible,
			SqlTypedMapping[] sqlTypedMappings,
			int selectionIndex,
			String selectionExpression,
			Set<String> compatibleTableExpressions,
			Set<? extends Attribute<?, ?>> attributes,
			EmbeddableValuedModelPart modelPartContainer) {
		final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
		int index = 0;
		for ( Attribute<?, ?> attribute : attributes ) {
			if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
				throw new IllegalArgumentException( "Only embeddables without collections are supported!" );
			}
			final DomainType<?> attributeType = ( (SingularPersistentAttribute<?, ?>) attribute ).getType();
			final ModelPart modelPart = AnonymousTupleTableGroupProducer.createModelPart(
					this,
					sqmExpressible,
					attributeType,
					sqlTypedMappings,
					selectionIndex + index,
					selectionExpression + "_" + attribute.getName(),
					attribute.getName(),
					modelPartContainer.findSubPart( attribute.getName(), null ),
					compatibleTableExpressions,
					index++
			);
			modelParts.put( modelPart.getPartName(), modelPart );
		}
		return modelParts;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the collection from the embeddable (embeddables with collections are a fragile mapping in general); model the collection on the owning entity instead
  2. Project only the singular attributes into the tuple and map the result to a DTO class rather than the embeddable
  3. Select the embeddable directly from its owning entity path rather than reconstructing it through a tuple/dynamic instantiation

Example fix

// before
@Embeddable
class Address {
    String city;
    @ElementCollection
    Set<String> phoneNumbers; // plural attribute breaks anonymous tuple part
}

// after
@Embeddable
class Address {
    String city;
}
// move phone numbers to the owning @Entity as @ElementCollection
Defensive patterns

Strategy: validation

Validate before calling

// Guard at mapping time: embeddables used in tuple/CTE projections must be singular-only
boolean hasPlural = embeddableType.getAttributes().stream().anyMatch(a -> !a.isCollection() == false); // i.e. a.isCollection()
if (hasPlural) throw new IllegalArgumentException("Embeddable " + embeddableType.getJavaType() + " has collection attributes; unsupported in tuple projections");

Type guard

static boolean isSingularOnly(ManagedType<?> type) { return type.getAttributes().stream().noneMatch(Attribute::isCollection); }

Try / catch

try { /* build tuple-typed query using the embeddable */ } catch (IllegalArgumentException e) { if (e.getMessage().contains("without collections")) { /* project singular attrs into a DTO instead */ } else throw e; }

Prevention

When it happens

Trigger: Projecting a tuple/CTE result whose type is an embeddable that contains a collection attribute, then using that tuple as an embeddable-valued path (e.g., CTE attribute typed as the embeddable, or a select-new instantiation later navigated as embeddable).

Common situations: Value-object embeddables that grew a @ElementCollection over time; criteria/HQL queries with CTEs typed by domain embeddables; upgrading to Hibernate 6 where anonymous tuple model parts now validate attributes strictly.

Related errors


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