hibernate/hibernate-orm · error · IllegalArgumentException

BindableType does not implement BindableTypeImplementor

Error message

BindableType does not implement BindableTypeImplementor

What it means

BindingContext.resolveExpressible(Type) (BindingContext.java:48-57) accepts a jakarta.persistence.metamodel.Type and must map it to Hibernate's internal SqmBindableType. It does so by checking whether the object is an org.hibernate.query.BindableType (the internal contract that carries resolveExpressible(BindingContext)); any other implementation of the JPA metamodel Type interface - from another provider, a hand-rolled wrapper, or a mock - is rejected with IllegalArgumentException 'BindableType does not implement BindableTypeImplementor'.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/BindingContext.java:56

	/**
	 * Resolve this parameter type to the corresponding {@link SqmBindableType}.
	 *
	 * @param <J> the type of the parameter
	 * @param bindableType the {@link BindableType} representing the type of the parameter,
	 *                     which may be null if the type is not known
	 * @return the corresponding {@link SqmBindableType}, or null if the argument was null
	 *
	 * @since 7.0
	 */
	default <J> @Nullable SqmBindableType<J> resolveExpressible(@Nullable Type<J> bindableType) {
		if ( bindableType == null ) {
			return null;
		}
		else if ( bindableType instanceof BindableType<J> implementor) {
			return implementor.resolveExpressible( this );
		}
		else {
			throw new IllegalArgumentException( "BindableType does not implement BindableTypeImplementor" );
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pass types obtained from Hibernate's own metamodel only, e.g. sessionFactory.getMetamodel().entity(...) / .embeddable(...), which are JpaMetamodel implementations of BindableType.
  2. If you wrap the metamodel, unwrap to the delegate before handing Types to BindingContext.resolveExpressible.
  3. For custom BindableType implementations, extend Hibernate's SQM type infrastructure rather than implementing the interface from scratch so resolveExpressible(BindingContext) is honored.
  4. In tests, build a real SessionFactory with test mappings instead of mocking the metamodel Type hierarchy.

Example fix

// before
Type<?> t = myWrapperMetamodel.entity(User.class); // custom wrapper Type
SqmBindableType<?> sqm = bindingContext.resolveExpressible(t); // throws

// after
Type<?> t = ((MetamodelImplementor) sessionFactory.getMetamodel())
        .entity(User.class); // Hibernate JpaEntityType implements BindableType
SqmBindableType<?> sqm = bindingContext.resolveExpressible(t);
Defensive patterns

Strategy: type-guard

Validate before calling

if (bindableType != null && !(bindableType instanceof org.hibernate.query.BindableType<?>)) {
    throw new IllegalArgumentException(
        "Expected a Hibernate BindableType implementation, got "
        + bindableType.getClass().getName());
}

Type guard

static boolean isHibernateBindable(jakarta.persistence.metamodel.Type<?> t) {
    return t instanceof org.hibernate.query.BindableType<?>;
}

Try / catch

try {
    return bindingContext.resolveExpressible(type);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("BindableTypeImplementor")) {
        // unwrap custom metamodel wrappers to the Hibernate delegate and retry
        return bindingContext.resolveExpressible(unwrapToHibernate(type));
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing a non-Hibernate implementation of jakarta.persistence.metamodel.Type (custom metamodel wrapper, mock from tests, another JPA provider's metamodel class) into BindingContext.resolveExpressible; writing a custom HQL/SQM function whose ArgumentsValidator or a TypecheckUtil path resolves caller-supplied JPA Type objects; implementing org.hibernate.query.BindableType yourself without following the internal resolution contract.

Common situations: Teams building SQM function libraries or criteria extensions on Hibernate's incubating 7.0 SPIs; tests stubbing the JPA metamodel with Mockito and feeding the stub into query validation; wrapping the metamodel for multi-tenancy or auditing and leaking the wrapper into Hibernate query APIs.

Related errors


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