hibernate/hibernate-orm · error · IllegalArgumentException

This class [{}] does not define an IdClass

Error message

This class [{}] does not define an IdClass

What it means

getIdClassAttributes() is only meaningful for entities mapped with @IdClass. The implementation first asserts hasIdClass(); for entities using a single @Id or @EmbeddedId this is false and Hibernate throws IllegalArgumentException per the JPA specification (the spec requires IllegalStateException for this precondition, Hibernate uses IllegalArgumentException here — either way it signals wrong API choice).

Source

Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractIdentifiableType.java:226

	 *
	 * @return IdClass attributes or {@code null}
	 */
	public Set<SingularPersistentAttribute<? super J, ?>> getIdClassAttributesSafely() {
		if ( hasIdClass() ) {
			final Set<SingularPersistentAttribute<? super J, ?>> attributes = new HashSet<>();
			visitIdClassAttributes( attributes::add );
			return attributes.isEmpty() ? null : attributes;
		}
		else {
			return null;
		}
	}

	@Override
	@Nonnull
	public Set<SingularAttribute<? super J, ?>> getIdClassAttributes() {
		if ( !hasIdClass() ) {
			throw new IllegalArgumentException( "This class [" + getJavaType() + "] does not define an IdClass" );
		}

		final Set<SingularAttribute<? super J, ?>> attributes = new HashSet<>();
		visitIdClassAttributes( attributes::add );
		if ( attributes.isEmpty() ) {
			throw new IllegalArgumentException( "Unable to locate IdClass attributes [" + getJavaType() + "]" );
		}
		return attributes;
	}

	@Override
	public void visitIdClassAttributes(@Nonnull Consumer<SingularPersistentAttribute<? super J, ?>> attributeConsumer) {
		if ( nonAggregatedIdAttributes != null ) {
			nonAggregatedIdAttributes.forEach( attributeConsumer );
		}
		else {
			final var superType = getSuperType();
			if ( superType != null ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Branch on hasIdClass() before calling getIdClassAttributes()
  2. For single-key entities use getId()/findIdAttribute(); for @EmbeddedId use the embedded id attribute
  3. Consider visitIdClassAttributes(), which visits nothing instead of throwing when there is no id class

Example fix

// before
Set<SingularAttribute<? super Order,?>> ids = orderType.getIdClassAttributes(); // @Id entity -> throws

// after
Set<SingularAttribute<? super Order,?>> ids =
    orderType.hasIdClass()
        ? orderType.getIdClassAttributes()
        : Set.of(orderType.getId(orderType.getIdType().getJavaType()));
Defensive patterns

Strategy: validation

Validate before calling

Set<SingularAttribute<? super E, ?>> idParts =
    identifiableType.hasIdClass()
        ? identifiableType.getIdClassAttributes()
        : Set.of();

Try / catch

try {
    return type.getIdClassAttributes();
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("does not define an IdClass")) {
        return Set.of(); // simple/embedded id: no id-class parts
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling identifiableType.getIdClassAttributes() on an entity that has a simple @Id or an @EmbeddedId instead of @IdClass. Generic key-handling code that unconditionally collects id-class attributes.

Common situations: Framework code that handles both key styles without checking hasIdClass() first. Changing an entity from @IdClass to @EmbeddedId without adapting callers.

Related errors


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