hibernate/hibernate-orm · error · IllegalStateException
Non-JPA classification: {}
Error message
Non-JPA classification: {} What it means
Hibernate's JPA metamodel attribute implementation cannot return a javax.persistence PersistentAttributeType because the attribute's Hibernate-specific AttributeClassification has no JPA equivalent. The only classification that maps to null is ANY (see AttributeClassification.getJpaClassification(), which returns null for ANY). Calling getPersistentAttributeType() on such an attribute therefore violates the JPA contract and Hibernate throws IllegalStateException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java:107
@Override
@Nonnull
public Member getJavaMember() {
return member;
}
@Override
@Nonnull
public AttributeClassification getAttributeClassification() {
return attributeClassification;
}
@Override
@Nonnull
public PersistentAttributeType getPersistentAttributeType() {
final var classification = getAttributeClassification().getJpaClassification();
if ( classification == null ) {
throw new IllegalStateException( "Non-JPA classification: " + attributeClassification );
}
return classification;
}
@Override
@Nonnull
public DomainType<?> getValueGraphType() {
return valueType;
}
NavigablePath getParentNavigablePath(SqmPath<?> parent) {
final var parentPathSource = parent.getResolvedModel();
final var parentType = parentPathSource.getPathType();
final var parentNavigablePath = buildParentNavigablePath( parent, "" );
if ( parentType != declaringType
&& parentType instanceof EntityDomainType<?> entityDomainType
&& entityDomainType.findAttribute( name ) == null ) {
// If the parent path is an entity type which does not contain theView on GitHub (pinned to fad1729dce)
Solutions
- Filter or branch on @Any-mapped attributes before calling getPersistentAttributeType(); use Hibernate's extended API getAttributeClassification() instead, which returns ANY
- Replace @Any mapping with a regular @ManyToOne to a common supertype or a join table if the JPA metamodel must be fully walkable
- Guard the call: if (attribute instanceof HibernateAttribute ha && ha.getAttributeClassification() == AttributeClassification.ANY) skip it
Example fix
// before
for (Attribute<?,?> a : managedType.getAttributes()) {
PersistentAttributeType t = a.getPersistentAttributeType(); // throws for @Any
}
// after
for (Attribute<?,?> a : managedType.getAttributes()) {
if (a.getPersistentAttributeType() == null) continue; // never reached; use try/catch or
if (a instanceof SingularAttribute<?,?> sa && "org.hibernate.metamodel.model.domain.SqmPathSource".isInstance(a)) {
// Hibernate extension: check classification first
}
PersistentAttributeType t = a.getPersistentAttributeType();
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before iterating, filter attributes by Hibernate's extended classification
import org.hibernate.metamodel.AttributeClassification;
for (Attribute<?,?> a : managedType.getAttributes()) {
if (a instanceof org.hibernate.metamodel.model.domain.internal.AbstractAttribute<?,?,?> hib
&& hib.getAttributeClassification() == AttributeClassification.ANY) {
continue; // @Any attribute: no JPA PersistentAttributeType
}
PersistentAttributeType t = a.getPersistentAttributeType();
} Type guard
static boolean hasJpaClassification(Attribute<?,?> a) {
return a instanceof org.hibernate.metamodel.model.domain.internal.AbstractAttribute<?,?,?> hib
&& hib.getAttributeClassification().getJpaClassification() != null;
} Try / catch
try {
PersistentAttributeType t = attr.getPersistentAttributeType();
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Non-JPA classification")) {
// @Any-mapped attribute: handle via Hibernate-specific classification
continue;
}
throw e;
} Prevention
- Prefer Hibernate's getAttributeClassification() over the JPA getPersistentAttributeType() in generic metamodel code
- Document which entities use @Any so framework code can special-case them
- Write one integration test that walks every entity's attributes through your metamodel utilities
When it happens
Trigger: Calling attribute.getPersistentAttributeType() on an attribute mapped with @Any / @AnyDiscriminator / hbm <any/> (AttributeClassification.ANY). Typically reached via the Criteria/JPA metamodel API, e.g. managedType.getAttributes().stream().map(a -> a.getPersistentAttributeType()), or via code that switches on PersistentAttributeType for every attribute of an entity.
Common situations: Entities using @Any polymorphic references (a column holding a discriminator plus a foreign key to any of several entities). Generic frameworks or utility code that walks the metamodel and assumes every attribute has a JPA classification. Migrating from Hibernate 5 where metamodel internals differed.
Related errors
- Unable to locate id type for type [{}]
- transformation of <any/> as part of <join/> (secondary-table
- Unable to interpret <meta-value value="%s" class="%s"/> defi
- Blobs may not be accessed after serialization
- Clobs may not be accessed after serialization
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/eee1dbe05d7161ff.
Report an issue: GitHub.