{"record":{"id":"4e825997d4054216","repo":"hibernate/hibernate-orm","slug":"could-not-resolve-attribute-of","errorCode":null,"errorMessage":"Could not resolve attribute '{}' of '{}'","messagePattern":"Could not resolve attribute '(.+?)' of '(.+?)'","errorType":"exception","errorClass":"PropertyNotFoundException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java","lineNumber":673,"sourceCode":"\n\tprivate static final MemberResolver virtualIdentifierMemberResolver = (attributeContext, metadataContext) -> {\n\t\tfinal var identifiableType = (AbstractIdentifiableType<?>) attributeContext.getOwnerType();\n\t\tfinal var declaringEntity = getDeclaringEntity( identifiableType, metadataContext );\n\t\treturn resolveVirtualIdentifierMember( attributeContext.getPropertyMapping(), declaringEntity );\n\t};\n\n\tprivate static Member resolveVirtualIdentifierMember( Property property, EntityPersister entityPersister) {\n\t\tfinal var identifierMapping = entityPersister.getIdentifierMapping();\n\t\tif ( identifierMapping.getNature() != EntityIdentifierMapping.Nature.VIRTUAL ) {\n\t\t\tthrow new IllegalArgumentException( \"expecting IdClass mapping\" );\n\t\t}\n\n\t\tfinal var cid = (CompositeIdentifierMapping) identifierMapping;\n\t\tfinal var embeddable = cid.getPartMappingType();\n\t\tfinal String attributeName = property.getName();\n\t\tfinal var attributeMapping = embeddable.findAttributeMapping( attributeName );\n\t\tif ( attributeMapping == null ) {\n\t\t\tthrow new PropertyNotFoundException(\n\t\t\t\t\t\"Could not resolve attribute '\" + attributeName\n\t\t\t\t\t\t\t+ \"' of '\" + embeddable.getJavaType().getJavaTypeClass().getName() + \"'\"\n\t\t\t);\n\t\t}\n\n\t\tfinal Getter getter = attributeMapping.getPropertyAccess().getGetter();\n\t\treturn getter instanceof PropertyAccessMapImpl.GetterImpl\n\t\t\t\t? new MapMember( attributeName, property.getType().getReturnedClass() )\n\t\t\t\t: getter.getMember();\n\t}\n\n\t/**\n\t * A {@link Member} resolver for normal attributes.\n\t */\n\tprivate static final MemberResolver normalMemberResolver = (attributeContext, metadataContext) -> {\n\t\tfinal var ownerType = attributeContext.getOwnerType();\n\t\tfinal Property property = attributeContext.getPropertyMapping();\n\t\tfinal var persistenceType = ownerType.getPersistenceType();","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java#L655-L691","documentation":"When the JPA metamodel is built for an entity with an IdClass (VIRTUAL identifier nature), AttributeFactory.resolveVirtualIdentifierMember looks up each IdClass property inside the CompositeIdentifierMapping's embeddable. If no attribute mapping with the property's name exists, Hibernate throws PropertyNotFoundException naming the attribute and the IdClass Java type. It almost always means the IdClass field names no longer line up with the entity's @Id property names.","triggerScenarios":"Building the JPA metamodel or a Criteria query for an @IdClass entity where the IdClass declares a field that is not one of the entity's @Id properties (or names differ by case/typo); an IdClass field removed from the entity but kept in the IdClass; property names renamed by refactoring only on one side.","commonSituations":"@IdClass + @Id derived identities (legacy pre-@MapsId pattern, e.g. JPA 1.0 era OrderLinePK); renames via IDE refactor updating entity but not the IdClass; copy-pasted IdClasses between entities; cases where the embeddable mapping is filtered (e.g. property marked @Transient or grouped into a subclass) while the IdClass still references it.","solutions":["Diff the IdClass fields against the entity's @Id properties — every IdClass field must have a same-named entity @Id property (exact name, same type).","Fix mismatches: rename the IdClass field or the entity property so both sides match.","Prefer @EmbeddedId or @EmbeddedId + @MapsId composite key patterns when possible — they tie the key fields to one embeddable and avoid this drift class of bugs.","Add a startup test that touches EntityManagerFactory.getMetamodel() for every entity so name drift fails CI, not production."],"exampleFix":"// before\npublic class OrderLinePK implements Serializable {\n    private Long order;     // entity property is named \"orderId\"\n    private Long product;\n}\n@IdClass(OrderLinePK.class)\npublic class OrderLine {\n    @Id private Long orderId;\n    @Id private Long product;\n}\n\n// after\npublic class OrderLinePK implements Serializable {\n    private Long orderId;   // matches entity property name\n    private Long product;\n}","handlingStrategy":"validation","validationCode":"// verify IdClass field names match the entity's @Id property names before bootstrap\nstatic void checkIdClass(Class<?> entity, Class<?> idClass) {\n    Set<String> ids = Arrays.stream(entity.getDeclaredFields())\n            .filter(f -> f.isAnnotationPresent(Id.class))\n            .map(Field::getName).collect(Collectors.toSet());\n    for (Field f : idClass.getDeclaredFields()) {\n        if (!ids.contains(f.getName()))\n            throw new IllegalStateException(\"IdClass field not an @Id property: \" + f.getName());\n    }\n}","typeGuard":"static boolean idClassMatches(Class<?> entity, Class<?> idClass) {\n    Set<String> ids = Arrays.stream(entity.getDeclaredFields())\n            .filter(f -> f.isAnnotationPresent(Id.class))\n            .map(Field::getName).collect(Collectors.toSet());\n    return Arrays.stream(idClass.getDeclaredFields()).map(Field::getName).allMatch(ids::contains);\n}","tryCatchPattern":"try {\n    emf.getMetamodel().entity(OrderLine.class);\n} catch (PropertyNotFoundException e) {\n    if (e.getMessage().startsWith(\"Could not resolve attribute\")) {\n        // IdClass/embeddable field drift — align names\n    }\n    throw e;\n}","preventionTips":["Keep IdClass fields exactly mirroring the entity's @Id properties (names and types).","Prefer @EmbeddedId for new composite keys — single source of truth for key fields.","Add a metamodel smoke test per entity to CI."],"tags":["hibernate","jpa-metamodel","idclass","composite-key","orm-mapping"],"backgroundTag":"idclass-field-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}