hibernate/hibernate-orm · error · CannotForceNonNullableException

Identifier property '" + getPath( holder, data ) + "' cannot

Error message

Identifier property '" + getPath( holder, data ) + "' cannot map to a '@Formula'

What it means

Thrown when an identifier property is mapped to a @Formula instead of a real column. During binding, PropertyBinder.forceColumnsNotNull forces every column backing an id to NOT NULL; a formula is a read-only SQL expression with no column, so CannotForceNonNullableException (an AnnotationException subclass) aborts bootstrap. It only fires when isId() is true for the property being bound.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java:1371

			Nullability nullability,
			MemberDetails property,
			AnnotatedColumns columns) {
		if ( shouldForceNotNull( nullability, isExplicitlyOptional( property ) ) ) {
			forceColumnsNotNull( propertyHolder, inferredData, columns );
		}

		setLazy( isLazy( property ) );
		setColumns( columns );
		makePropertyValueAndBind();
	}

	private void forceColumnsNotNull(
			PropertyHolder holder,
			PropertyData data,
			AnnotatedColumns columns) {
		for ( AnnotatedColumn column : columns.getColumns() ) {
			if ( isId() && column.isFormula() ) {
				throw new CannotForceNonNullableException( "Identifier property '"
						+ getPath( holder, data ) + "' cannot map to a '@Formula'" );
			}
			column.forceNotNull();
		}
	}

	private boolean shouldForceNotNull(Nullability nullability, boolean optional) {
		return isId()
			|| !optional && nullability != Nullability.FORCED_NULL;
	}

	/**
	 * Should this property be considered optional, without considering
	 * whether it is primitive?
	 *
	 * @apiNote Poorly named to a degree.
	 *          The intention is really whether non-optional is explicit
	 */

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove @Formula from the identifier attribute and map it to a real column with @Column(name = ...).
  2. If the key value is computed in SQL, generate it in the database (generated column, trigger, or default) and map the resulting column normally.
  3. If the id should be synthetic, use @Id @GeneratedValue with a proper id column instead of deriving it from an expression.
  4. Restructure view-backed entities so the id maps to a plain (non-formula) column of the view.

Example fix

// before
@Id
@Formula("regexp_replace(code, 'X', '')")
private Long id;

// after
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private Long id;
Defensive patterns

Strategy: validation

Validate before calling

// CI guard: boot the mapping cheaply and fail fast on bad id formulas
Metadata metadata = new MetadataSources(new StandardServiceRegistryBuilder().build())
        .addAnnotatedClass(Order.class)
        .buildMetadata(); // throws CannotForceNonNullableException here, not in production

Try / catch

try {
    sessionFactory = metadata.buildSessionFactory();
} catch (AnnotationException e) { // CannotForceNonNullableException extends AnnotationException
    throw new IllegalStateException("Mapping rejected: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Entity declares @Id on a field/getter that also carries @Formula("..."), or an @EmbeddedId embeddable whose member uses @Formula. Raised while Hibernate binds the id property and iterates its AnnotatedColumns, never at runtime.

Common situations: Trying to use a computed/derived SQL expression as the primary key; aliasing real columns with @Formula and accidentally applying it to the id; mapping an entity to a database view and marking a view column formula-based; copying @Formula conventions from read-only attributes onto identifiers.

Related errors


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