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 the

View on GitHub (pinned to fad1729dce)

Solutions

  1. Filter or branch on @Any-mapped attributes before calling getPersistentAttributeType(); use Hibernate's extended API getAttributeClassification() instead, which returns ANY
  2. Replace @Any mapping with a regular @ManyToOne to a common supertype or a join table if the JPA metamodel must be fully walkable
  3. 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

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


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/eee1dbe05d7161ff. Report an issue: GitHub.