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
- Pass types obtained from Hibernate's own metamodel only, e.g. sessionFactory.getMetamodel().entity(...) / .embeddable(...), which are JpaMetamodel implementations of BindableType.
- If you wrap the metamodel, unwrap to the delegate before handing Types to BindingContext.resolveExpressible.
- For custom BindableType implementations, extend Hibernate's SQM type infrastructure rather than implementing the interface from scratch so resolveExpressible(BindingContext) is honored.
- 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
- Always source metamodel Type objects from Hibernate's own Metamodel (sessionFactory.getMetamodel()).
- If you wrap the metamodel, expose the underlying delegate to Hibernate-facing code; never feed wrappers into SQM APIs.
- Avoid mocking the JPA metamodel in tests of Hibernate SPI extensions; use a small real SessionFactory.
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
- Could not resolve attribute '%s' of '%s'
- Not a treatable type: ${treatJavaType.getName()}
- Informix does not support binary literals
- immutable global instance of LockOptions
- Non-terminal property path did not reference FetchableContai
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/67ab072d051f547f.
Report an issue: GitHub.