hibernate/hibernate-orm · error · UnsupportedOperationException
Can't infer collection type based on element expression: {}
Error message
Can't infer collection type based on element expression: {} What it means
When a criteria value/parameter binding wraps a java.util.Collection, Hibernate tries to determine the collection's element BasicType from an 'element type inference source' expression. collectionValueParameter resolves that expression's SqmType; if it is null (the expression is untyped — e.g. a raw parameter or an expression whose type was never resolvable), it throws UnsupportedOperationException because it cannot pick a list SqlType for the bind.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java:2632
final Object coercedValue = javaType.coerce( value );
// ignore typeInferenceSource and fall back to the value type
if ( isInstance( bindableType, coercedValue ) ) {
@SuppressWarnings("unchecked") // safe, we just checked
final var widerType = (BindableType<? super T>) bindableType;
return new ValueBindJpaCriteriaParameter<>( widerType, javaType.cast( coercedValue ), this );
}
else {
return new ValueBindJpaCriteriaParameter<>( getParameterBindType( value ), value, this );
}
}
}
private <E> ValueBindJpaCriteriaParameter<? extends Collection<E>> collectionValueParameter(Collection<E> value, SqmExpression<E> elementTypeInferenceSource) {
final var elementType =
resolveExpressible( bindableType( elementTypeInferenceSource ) )
.getSqmType();
if ( elementType == null ) {
throw new UnsupportedOperationException( "Can't infer collection type based on element expression: " + elementTypeInferenceSource );
}
final var collectionType = DdlTypeHelper.resolveListType( elementType, getTypeConfiguration() );
//noinspection unchecked
return new ValueBindJpaCriteriaParameter<>( (BasicType<Collection<E>>) collectionType, value, this );
}
private static <E> BindableType<E> bindableType(SqmExpression<E> elementTypeInferenceSource) {
if ( elementTypeInferenceSource != null ) {
if ( elementTypeInferenceSource instanceof BindableType ) {
//noinspection unchecked
return (BindableType<E>) elementTypeInferenceSource;
}
else if ( elementTypeInferenceSource.getNodeType() != null ) {
return elementTypeInferenceSource.getNodeType();
}
}
return null;
}View on GitHub (pinned to fad1729dce)
Solutions
- Give the inference source a concrete type: bind against a typed path (root.get("status")) or wrap the value with an explicitly typed parameter (cb.parameter(List.class) plus setParameter with typed list).
- Prefer the standard IN pattern: path.in(collection) or cb.in(path).value(...), which types itself from the path.
- If the element type is known up front, construct the ValueBindJpaCriteriaParameter with an explicitly typed expression (e.g. cb.literal(firstElement) or cb.treat(...)/cb.as(...) cast).
Example fix
// before
Expression<Collection<String>> in = cb.value(statusCodes); // element expression untyped -> UnsupportedOperationException
// after
Predicate p = root.get("status").in(statusCodes); // typed from the path
// or with an explicit parameter:
ParameterExpression<List<String>> p1 = cb.parameter(List.class);
query.where(root.get("status").in(p1));
q.setParameter(p1, statusCodes); Defensive patterns
Strategy: validation
Validate before calling
// Bind collections through typed paths/parameters instead of untyped value binds
boolean pathTyped(Expression<?> e) {
return e instanceof Path<?> p && p.getModel() != null;
}
if (!pathTyped(elementSource)) throw new IllegalArgumentException("need a typed path to infer collection element type"); Type guard
static boolean hasResolvableType(Expression<?> e) {
return e instanceof Path<?> p && p.getModel() != null; // paths carry attribute types
} Try / catch
try {
expr = cb.value(statusCodes); // collection bind
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("infer collection type")) { /* use root.get("status").in(statusCodes) instead */ }
else throw e;
} Prevention
- Prefer path.in(collection) for IN-lists — the path supplies the element type.
- Always pair collection values with a typed inference source (a path or explicitly typed parameter).
- Avoid generic Expression<?> placeholders in filter frameworks; keep the driving path in the predicate.
When it happens
Trigger: Passing a Collection value through cb.value(collection) / ValueBindJpaCriteriaParameter creation where the inference-source expression is itself an untyped JpaCriteriaParameter or a generic SqmExpression with null SqmType; building IN-list bindings dynamically against an expression that carries no type information.
Common situations: Generic filter frameworks that bind collections via value(...) against opaque Expression<?> placeholders; reusing an expression taken from a different builder/query before its type was established; Hibernate version changes that tightened when expression types get resolved.
Related errors
- Could not determine ValueMapping for SqmExpression: {}
- Could not determine ValueMapping for SqmParameter: {}
- Could not determine neither the SqlTypedMapping nor the Bind
- Informix does not support binary literals
- Unable to locate JdbcValueDescriptor for column `%s`
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/8b687f486f31e08c.
Report an issue: GitHub.