hibernate/hibernate-orm · error · IllegalArgumentException
Unable to unwrap to {}
Error message
Unable to unwrap to {} What it means
SqmCriteriaNodeBuilder.unwrap(Class) only resolves classes registered in its internal 'extensions' map; it is not a general JPA-style unwrap that adapts to arbitrary target types. Asking for any class not present in that registry throws IllegalArgumentException with the requested class name. In practice the map contains the node builder's own registered extensions (first and foremost SqmCriteriaNodeBuilder/HibernateCriteriaBuilder itself).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java:918
@Override
public SqmPredicate wrap(List<? extends Expression<Boolean>> restrictions) {
if ( restrictions.size() == 1 ) {
return wrap( restrictions.get( 0 ) );
}
else {
final List<SqmPredicate> predicates = new ArrayList<>( restrictions.size() );
for ( var expression : restrictions ) {
predicates.add( wrap( expression ) );
}
return new SqmJunctionPredicate( Predicate.BooleanOperator.AND, predicates, this );
}
}
@Override @SuppressWarnings("unchecked")
public <T extends HibernateCriteriaBuilder> T unwrap(Class<T> clazz) {
final T result = (T) extensions.get( clazz );
if ( result == null ) {
throw new IllegalArgumentException( "Unable to unwrap to " + clazz.getName() );
}
return result;
}
@Override
public SqmPath<?> fk(Path<?> path) {
final var sqmPath = (SqmPath<?>) path;
final var toOneReference = sqmPath.getReferencedPathSource();
final boolean validToOneRef =
toOneReference.getBindableType() == Bindable.BindableType.SINGULAR_ATTRIBUTE
&& toOneReference instanceof EntitySqmPathSource;
if ( !validToOneRef ) {
throw new FunctionArgumentException(
String.format(
Locale.ROOT,
"Argument '%s' of 'fk()' function is not a single-valued association",
sqmPath.getNavigablePath()
)View on GitHub (pinned to fad1729dce)
Solutions
- Remove the unwrap call: the object you get from session.getCriteriaBuilder() already IS the HibernateCriteriaBuilder — assign it directly (HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) session.getCriteriaBuilder()).
- To reach the Session/SessionFactory, unwrap the EntityManager/Session instead of the CriteriaBuilder (em.unwrap(Session.class)).
- If you truly need a specific extension, unwrap only to the documented target: cb.unwrap(HibernateCriteriaBuilder.class) or SqmCriteriaNodeBuilder.class.
Example fix
// before Session s = criteriaBuilder.unwrap(Session.class); // Unable to unwrap to org.hibernate.Session // after Session s = em.unwrap(Session.class); HibernateCriteriaBuilder hcb = (HibernateCriteriaBuilder) criteriaBuilder;
Defensive patterns
Strategy: type-guard
Validate before calling
// unwrap() only resolves registered criteria-builder extensions; probe the known ones
Object ext = null;
for (Class<?> c : List.of(HibernateCriteriaBuilder.class, SqmCriteriaNodeBuilder.class)) {
try { ext = criteriaBuilder.unwrap(c); break; } catch (IllegalArgumentException ignored) { }
} Type guard
static boolean isUnwrappableCriteriaExtension(CriteriaBuilder cb, Class<?> target) {
return target == HibernateCriteriaBuilder.class
|| target == SqmCriteriaNodeBuilder.class; // registered extension types Try / catch
try {
HibernateCriteriaBuilder hcb = criteriaBuilder.unwrap(HibernateCriteriaBuilder.class);
} catch (IllegalArgumentException e) {
// not a registered extension: cast directly instead (the object already implements it)
HibernateCriteriaBuilder hcb = (HibernateCriteriaBuilder) criteriaBuilder;
} Prevention
- Never unwrap the CriteriaBuilder to reach the Session/EntityManagerFactory; unwrap the EntityManager instead.
- Prefer direct casting: what you get from session.getCriteriaBuilder() already implements HibernateCriteriaBuilder.
- Reserve unwrap() calls for APIs that document the supported targets.
When it happens
Trigger: criteriaBuilder.unwrap(Session.class), unwrap(SessionFactory.class), unwrap(MyCustomBuilder.class), or any jakarta.persistence interface other than a registered criteria-builder extension.
Common situations: Generic framework code that defensively calls unwrap(SomeApi.class) on every JPA object (works on EntityManager, fails here); migrating code from EclipseLink/OpenJPA where unwrap is more permissive; attempting to reach the Session from the CriteriaBuilder.
Related errors
- Hibernate cannot unwrap EntityManagerFactory as '{type.getNa
- Selection item in a multi-select cannot contain compound arr
- Selection item in a multi-select cannot contain compound tup
- Informix does not support binary literals
- Class '<componentClassName>' is an '@Embeddable' type and ma
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/853589a237044994.
Report an issue: GitHub.