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

  1. Remove the unwrap call: the object you get from session.getCriteriaBuilder() already IS the HibernateCriteriaBuilder — assign it directly (HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) session.getCriteriaBuilder()).
  2. To reach the Session/SessionFactory, unwrap the EntityManager/Session instead of the CriteriaBuilder (em.unwrap(Session.class)).
  3. 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

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


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