hibernate/hibernate-orm · error · SemanticException

Cannot compare left expression of type '%s' with right expre

Error message

Cannot compare left expression of type '%s' with right expression of type '%s'

What it means

SqmMemberOfPredicate's constructor throws SemanticException when the left-hand expression of a MEMBER OF test is not type-comparable with the element type of the plural path. Hibernate resolves the collection's element type (`pluralPath.getPluralAttribute().getElementType()`) and runs TypecheckUtil.areTypesComparable against the left expression's node type; `x member of y` is only valid when x could be an element of y (same type, or comparable basic/super/sub type). The check fails fast during SQM construction.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/predicate/SqmMemberOfPredicate.java:47

	public SqmMemberOfPredicate(SqmExpression<?> leftHandExpression, SqmPluralValuedSimplePath<?> pluralPath, NodeBuilder nodeBuilder) {
		this( leftHandExpression, pluralPath, false, nodeBuilder );
	}

	public SqmMemberOfPredicate(
			SqmExpression<?> leftHandExpression,
			SqmPluralValuedSimplePath<?> pluralPath,
			boolean negated,
			NodeBuilder nodeBuilder) {
		super( negated, nodeBuilder );

		this.pluralPath = pluralPath;
		this.leftHandExpression = leftHandExpression;

		final SimpleDomainType<?> elementType = pluralPath.getPluralAttribute().getElementType();
		final SqmBindableType<?> simpleDomainType = nodeBuilder.resolveExpressible( elementType );

		if ( !areTypesComparable( leftHandExpression.getNodeType(), simpleDomainType, nodeBuilder ) ) {
			throw new SemanticException(
					String.format(
							"Cannot compare left expression of type '%s' with right expression of type '%s'",
							castNonNull( leftHandExpression.getNodeType() ).getTypeName(),
							pluralPath.getNodeType().getTypeName()
					)
			);
		}

		leftHandExpression.applyInferableType( simpleDomainType );
	}

	@Override
	public SqmMemberOfPredicate copy(SqmCopyContext context) {
		final SqmMemberOfPredicate existing = context.getCopy( this );
		if ( existing != null ) {
			return existing;
		}
		final SqmMemberOfPredicate predicate = context.registerCopy(

View on GitHub (pinned to fad1729dce)

Solutions

  1. Make the left expression's type match the collection element type — check `pluralPath.getPluralAttribute().getElement().getJavaType()`
  2. For element collections of basics, compare the basic value: `where 'x' member of p.tags`
  3. For entity collections, use the entity-typed path/parameter: `where :order member of customer.orders`
  4. If you meant scalar containment over a basic collection, use `path in (...)` against the collection instead of member of

Example fix

// before
// Order.lines is List<OrderLine> (entity elements)
session.createQuery("from Order o where 1 member of o.lines", Order.class); // SemanticException

// after
session.createQuery("from Order o where :line member of o.lines", Order.class)
        .setParameter("line", lineRef);
Defensive patterns

Strategy: validation

Validate before calling

import jakarta.persistence.metamodel.PluralAttribute;

Class<?> elementType = ((PluralAttribute<?, ?, ?>) path.getModel()).getElementType().getJavaType();
if (!elementType.isAssignableFrom(leftExpr.getJavaType())) {
    throw new IllegalArgumentException("MEMBER OF left side must be " + elementType + ", got " + leftExpr.getJavaType());
}
cb.isMember(leftExpr, path);

Try / catch

try { session.createQuery(hql).list(); }
catch (org.hibernate.query.SemanticException e) {
    // 'Cannot compare left expression...' -> fix the left-side type in the query string
    throw e;
}

Prevention

When it happens

Trigger: HQL `where 1 member of p.names` where names is Collection<String>; `where p.id member of o.lines` (Long vs OrderLine); criteria `cb.isMember( cb.literal(1), person.get("names") )`; binding a parameter of the wrong Java type via `setParameter` when the left expression is an untyped parameter whose inferred type mismatches the element type.

Common situations: Copying MEMBER OF from SQL IN intuitions (IN compares scalars, MEMBER OF compares entities/elements with collections); schema refactors that changed an element collection's element type (String → enum, Long → UUID) while old queries remain; passing the entity itself instead of its id, or the id instead of the entity, on either side.

Related errors


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