{"record":{"id":"d0bd7128bd1fb470","repo":"hibernate/hibernate-orm","slug":"illegal-call-to-identifiabletype-getid-for-class","errorCode":null,"errorMessage":"Illegal call to IdentifiableType#getId for class [{}] defined with @IdClass","messagePattern":"Illegal call to IdentifiableType#getId for class \\[(.+?)\\] defined with @IdClass","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractIdentifiableType.java","lineNumber":135,"sourceCode":"\t\treturn getSuperType();\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic <Y> SqmSingularPersistentAttribute<? super J, Y> getId(Class<Y> javaType) {\n\t\tensureNoIdClass();\n\t\tfinal var id = findIdAttribute();\n\t\tif ( id != null ) {\n\t\t\tcheckType( id, javaType );\n\t\t}\n\t\t@SuppressWarnings(\"unchecked\") // safe, we just checked\n\t\tfinal var castId = (SqmSingularPersistentAttribute<? super J, Y>) id;\n\t\treturn castId;\n\t}\n\n\tprivate void ensureNoIdClass() {\n\t\tif ( hasIdClass() ) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Illegal call to IdentifiableType#getId for class [\" + getTypeName() + \"] defined with @IdClass\"\n\t\t\t);\n\t\t}\n\t}\n\n\n\t@Override\n\tpublic @Nullable SqmSingularPersistentAttribute<? super J, ?> findIdAttribute() {\n\t\tif ( id != null ) {\n\t\t\treturn id;\n\t\t}\n\t\telse if ( getSuperType() != null ) {\n\t\t\treturn getSuperType().findIdAttribute();\n\t\t}\n\t\telse {\n\t\t\treturn null;\n\t\t}\n\t}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractIdentifiableType.java#L117-L153","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nSingularAttribute<? super Order, Long> id = orderType.getId(Long.class); // @IdClass -> throws\n\n// after\nif (orderType.hasIdClass()) {\n    Set<SingularAttribute<? super Order,?>> parts = orderType.getIdClassAttributes();\n} else {\n    SingularAttribute<? super Order, Long> id = orderType.getId(Long.class);\n}","handlingStrategy":"validation","validationCode":"if (identifiableType.hasIdClass()) {\n    Set<SingularAttribute<? super E, ?>> parts = identifiableType.getIdClassAttributes();\n} else {\n    SingularAttribute<? super E, ?> id = identifiableType.getId(idJavaType(identifiableType));\n}","typeGuard":null,"tryCatchPattern":"try {\n    return identifiableType.getId(type);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"defined with @IdClass\")) {\n        return null; // caller must use getIdClassAttributes()\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["hibernate","jpa-metamodel","idclass","composite-key","illegal-argument"],"backgroundTag":"jpa-composite-id-misuse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}