hibernate/hibernate-orm · error · IllegalArgumentException
Id not an instance of type " + type.getName()
Error message
Id not an instance of type " + type.getName()
What it means
EntityJavaType unwraps an entity reference to its identifier when the value must be bound to JDBC. It extracts the id via the entity persister, checks the requested target type with type.isInstance(id), and throws IllegalArgumentException when the binder's expected class differs from the entity's actual identifier class (e.g. String requested but the id is Long, or the id is composite).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/EntityJavaType.java:68
final var lazyInitializer = extractLazyInitializer( value );
final var javaTypeClass = getJavaTypeClass();
if ( lazyInitializer != null ) {
return javaTypeClass.isAssignableFrom( lazyInitializer.getPersistentClass() )
|| javaTypeClass.isAssignableFrom( lazyInitializer.getImplementationClass() );
}
else {
return javaTypeClass.isAssignableFrom( value.getClass() );
}
}
@Override
public <X> X unwrap(T value, Class<X> type, WrapperOptions options) {
final var id =
options.getSessionFactory().getMappingMetamodel()
.getEntityDescriptor( getJavaTypeClass() )
.getIdentifier( value );
if ( !type.isInstance( id ) ) {
throw new IllegalArgumentException( "Id not an instance of type " + type.getName() );
}
return type.cast( value );
}
@Override
public <X> T wrap(X value, WrapperOptions options) {
final var entityClass = getJavaTypeClass();
final var persister =
options.getSessionFactory().getMappingMetamodel()
.getEntityDescriptor( entityClass );
final var idType = persister.getIdentifierType().getReturnedClass();
if ( !idType.isInstance( value ) ) {
throw new IllegalArgumentException( "Not an instance of id type " + idType.getName() );
}
final var entity =
options.getSession()
.internalLoad( persister.getEntityName(), value, false, true );
return entityClass.cast( entity );View on GitHub (pinned to fad1729dce)
Solutions
- Bind the identifier explicitly — use entity.getId() as the parameter value instead of the entity
- Align the requested unwrap type with the real identifier class (check persister.getIdentifierType().getReturnedClass())
- For composite keys, bind the id-class object or each component separately
- Update custom JavaType/JdbcType integrations to request the exact id class the entity declares
Example fix
// before
nativeQuery.setParameter("owner", ownerEntity); // binder unwraps to id class, mismatch -> throws
// after
nativeQuery.setParameter("owner", ownerEntity.getId()); // bind the id itself Defensive patterns
Strategy: type-guard
Validate before calling
Class<?> idClass = session.getFactory().getMappingMetamodel()
.getEntityDescriptor(Owner.class)
.getIdentifierType().getReturnedClass();
if (!idClass.isInstance(valueToBind)) {
throw new IllegalArgumentException("expected id type " + idClass.getName());
} Type guard
static boolean idTypeMatches(SessionFactory sf, Class<?> entity, Object candidateId) {
Class<?> idClass = sf.getMappingMetamodel()
.getEntityDescriptor(entity).getIdentifierType().getReturnedClass();
return idClass.isInstance(candidateId);
} Try / catch
try {
query.setParameter("owner", owner);
} catch (IllegalArgumentException e) {
// unwrap/id mismatch: bind the identifier directly instead
query.setParameter("owner", owner.getId());
} Prevention
- Bind ids, not entity instances, to native queries
- Keep one source of truth for id types across services
- Smoke-test parameter binding after any @Id type change
- Check persister.getIdentifierType().getReturnedClass() when writing generic binders
When it happens
Trigger: Binding a whole entity as a query parameter where the JDBC binder unwraps it to an id class that does not match; unwrap() calls with a wrong Class on an entity-typed attribute; @IdClass/@EmbeddedId composite ids flowing into single-column bind paths; custom types requesting an id class the entity does not use.
Common situations: Switching an @Id field from Long to a custom value object or UUID without updating consumers; native queries binding entities instead of ids; entity hierarchies where getIdentifier() returns a different runtime class than integrations assume.
Related errors
- Identifier property '" + getPath( holder, data ) + "' cannot
- An association from the table '" + getTable().getName() + "'
- identifier mapping has wrong number of columns: " + getEntit
- Unknown unwrap conversion requested: " + type.getTypeName()
- Unwrap strategy not known for this Java type: " + getTypeNam
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/72222f25d5773703.
Report an issue: GitHub.