hibernate/hibernate-orm · error · IllegalArgumentException
Illegal call to IdentifiableType#getId for class [{}] define
Error message
Illegal call to IdentifiableType#getId for class [{}] defined with @IdClass What it means
JPA's IdentifiableType#getId(Y) only supports a single id attribute or an aggregated @EmbeddedId. When the entity uses @IdClass (a non-aggregated composite id made of several @Id fields), there is no single id attribute to return, so Hibernate throws IllegalArgumentException. This mirrors the behavior mandated by the JPA specification.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractIdentifiableType.java:135
return getSuperType();
}
@Override
@Nonnull
public <Y> SqmSingularPersistentAttribute<? super J, Y> getId(Class<Y> javaType) {
ensureNoIdClass();
final var id = findIdAttribute();
if ( id != null ) {
checkType( id, javaType );
}
@SuppressWarnings("unchecked") // safe, we just checked
final var castId = (SqmSingularPersistentAttribute<? super J, Y>) id;
return castId;
}
private void ensureNoIdClass() {
if ( hasIdClass() ) {
throw new IllegalArgumentException(
"Illegal call to IdentifiableType#getId for class [" + getTypeName() + "] defined with @IdClass"
);
}
}
@Override
public @Nullable SqmSingularPersistentAttribute<? super J, ?> findIdAttribute() {
if ( id != null ) {
return id;
}
else if ( getSuperType() != null ) {
return getSuperType().findIdAttribute();
}
else {
return null;
}
}View on GitHub (pinned to fad1729dce)
Solutions
- Use getIdClassAttributes() (or visitIdClassAttributes) to obtain the set of id attributes for @IdClass entities
- Switch the entity to a single @Id or an @EmbeddedId if your framework requires getId(); @EmbeddedId supports getId() via the embedded attribute
- Branch first: if (entityType.hasIdClass()) ... else entityType.getId(...) — hasIdClass() is the cheap guard
Example fix
// before
SingularAttribute<? super Order, Long> id = orderType.getId(Long.class); // @IdClass -> throws
// after
if (orderType.hasIdClass()) {
Set<SingularAttribute<? super Order,?>> parts = orderType.getIdClassAttributes();
} else {
SingularAttribute<? super Order, Long> id = orderType.getId(Long.class);
} Defensive patterns
Strategy: validation
Validate before calling
if (identifiableType.hasIdClass()) {
Set<SingularAttribute<? super E, ?>> parts = identifiableType.getIdClassAttributes();
} else {
SingularAttribute<? super E, ?> id = identifiableType.getId(idJavaType(identifiableType));
} Try / catch
try {
return identifiableType.getId(type);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("defined with @IdClass")) {
return null; // caller must use getIdClassAttributes()
}
throw e;
} Prevention
- Always branch on hasIdClass() before getId()/getDeclaredId()
- Prefer @EmbeddedId for new composite keys — it works with getId()
- Encapsulate id resolution in one utility instead of scattering getId calls
When it happens
Trigger: Calling entityType.getId(javaType) or getDeclaredId(javaType) on a ManagedType whose entity class is annotated with @IdClass(MyIdClass.class). Common in generic DAO frameworks that auto-resolve 'the id attribute' for every entity.
Common situations: Generic repository/base-entity code that assumes every entity has exactly one @Id. Legacy schemas with composite keys modeled via @IdClass. Migrating code from a single-key entity to a composite key without updating the id-access utilities.
Related errors
- This class [{}] does not define an IdClass
- Could not resolve attribute '{}' of '{}'
- Unable to locate IdClass attributes [{}]
- Property '" + getPath( propertyHolder, inferredData ) + "' b
- The version attribute is not declared or inherited by this t
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/d0bd7128bd1fb470.
Report an issue: GitHub.