hibernate/hibernate-orm · error · AnnotationException

'@Check' may only be applied to single-column mappings but '

Error message

'@Check' may only be applied to single-column mappings but '${name}' maps to ${length} columns (use a table-level '@Check')

What it means

AnnotatedColumn.applyColumnCheckConstraint turns a property-level @Check into a column-level CHECK constraint, which can only be attached to a single column. If the annotated member maps a number of columns other than 1, binding fails with this AnnotationException, and the message itself points you to a table-level '@Check'.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java:990

		}
	}

	void applyCheckConstraint(PropertyData inferredData, int length) {
		final var memberDetails = inferredData.getAttributeMember();
		if ( memberDetails != null ) {
			// if there are multiple annotations, they're not overrideable
			final var checksAnn = memberDetails.getDirectAnnotationUsage( Checks.class );
			if ( checksAnn != null ) {
				final var checkAnns = checksAnn.value();
				for ( var checkAnn : checkAnns ) {
					addCheckConstraint( nullIfBlank( checkAnn.name() ), checkAnn.constraints() );
				}
			}
			else {
				final var checkAnn = getOverridableAnnotation( memberDetails, Check.class, getBuildingContext() );
				if ( checkAnn != null ) {
					if ( length != 1 ) {
						throw new AnnotationException("'@Check' may only be applied to single-column mappings but '"
								+ memberDetails.getName() + "' maps to " + length + " columns (use a table-level '@Check')" );
					}
					addCheckConstraint( nullIfBlank( checkAnn.name() ), checkAnn.constraints() );
				}
			}
		}
		else {
			BOOT_LOGGER.couldNotPerformCheckLookup();
		}
	}

	//must only be called after all setters are defined and before binding
	private void extractDataFromPropertyData(
			PropertyHolder propertyHolder,
			PropertyData inferredData,
			ModelsContext context) {
		if ( inferredData != null ) {
			final var memberDetails = inferredData.getAttributeMember();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the property-level @Check and declare a table-level check instead: @Table(checks = @Check(...)) on the entity (or class-level @Check)
  2. Alternatively apply @Check to the exact single-column field inside the embeddable
  3. Verify the constraint expression references only columns of that one property if kept at column level

Example fix

// before: column-level @Check on a multi-column property
@Entity
public class Booking {
    @Check(name = "valid_range", constraints = "start_date <= end_date")  // 2 columns -> error
    @Embedded
    private DateRange range;
}

// after: table-level check
@Entity
@Table(checks = @Check(name = "valid_range", constraints = "start_date <= end_date"))
public class Booking {
    @Embedded
    private DateRange range;   // maps start_date / end_date
}
Defensive patterns

Strategy: validation

Validate before calling

// Before boot: property-level @Check must not sit on embedded/multi-column attributes
static boolean propertyChecksAreSingleColumn(Class<?> entity) {
    for (Field f : entity.getDeclaredFields()) {
        if (f.isAnnotationPresent(Check.class) && !f.isAnnotationPresent(Checks.class)
                && (f.isAnnotationPresent(Embedded.class) || f.isAnnotationPresent(Columns.class))) {
            return false;
        }
    }
    return true;
}

Try / catch

try {
    final SessionFactory sf = new MetadataSources(standardServiceRegistry)
            .addAnnotatedClass(MyEntity.class)
            .buildMetadata()
            .buildSessionFactory();
} catch (AnnotationException | MappingException e) {
    throw new IllegalStateException("Invalid ORM mapping, aborting startup: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: A property-level @org.hibernate.annotations.Check on an @Embedded attribute, a composite basic type (@Columns), or other multi-column mapping during metadata binding.

Common situations: Annotating embedded/composite attributes with @Check; teams familiar with table-level checks applying the annotation at field level; refactoring a single-column field into a composite while leaving @Check behind.

Related errors


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