hibernate/hibernate-orm · error · MappingException

one-to-one attribute [%s] cannot specify orphan delete casca

Error message

one-to-one attribute [%s] cannot specify orphan delete cascading as it is constrained

What it means

A <one-to-one> with constrained='true' stores its FK on this entity pointing at the referenced entity; the referenced row's lifecycle is bound to the owning row, so orphan-removal semantics are not applicable. Hibernate therefore rejects any cascade style containing delete-orphan on a constrained one-to-one at bind time, before the SessionFactory is built.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java:1905

		if ( cascadeStyleName != null && cascadeStyleName.contains( "delete-orphan" )
				&& !manyToOneBinding.isLogicalOneToOne() ) {
			throw new MappingException(
					"""
					many-to-one attribute [%s] specified delete-orphan but is not specified as unique; \
					remove delete-orphan cascading or specify unique="true"
					"""
							.formatted( manyToOneSource.getAttributeRole().getFullPath() ),
					sourceDocument.getOrigin()
			);
		}
	}

	private static void checkConstrainedOneToOneOrphanDelete(
			MappingDocument sourceDocument,
			SingularAttributeSourceOneToOne oneToOneSource) {
		final String cascadeStyleName = oneToOneSource.getCascadeStyleName();
		if ( cascadeStyleName != null && cascadeStyleName.contains( "delete-orphan" ) ) {
			throw new MappingException(
					"one-to-one attribute [%s] cannot specify orphan delete cascading as it is constrained"
							.formatted( oneToOneSource.getAttributeRole().getFullPath() ),
					sourceDocument.getOrigin()
			);
		}
	}

	private void bindManyToOneAttribute(
			final MappingDocument sourceDocument,
			final SingularAttributeSourceManyToOne manyToOneSource,
			ManyToOne manyToOneBinding,
			String referencedEntityName) {
		// NOTE: no type information to bind

		handleReferencedEntity( manyToOneBinding, referencedEntityName,
				manyToOneSource.getReferencedEntityAttributeName() );

		handleFetchCharacteristics( manyToOneSource, manyToOneBinding );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove delete-orphan from the cascade of the constrained one-to-one
  2. If orphan-removal behavior is needed, put it on the owning (FK-holding, unconstrained) side of the association
  3. Note the constrained row is removed with its owner via the FK anyway, so cascade='delete' on the owner is usually sufficient

Example fix

// before
<one-to-one name='employee' class='Employee' constrained='true' cascade='all-delete-orphan'/>

// after
<one-to-one name='employee' class='Employee' constrained='true' cascade='all'/>
Defensive patterns

Strategy: validation

Validate before calling

NodeList otos = doc.getElementsByTagName("one-to-one");
for (int i = 0; i < otos.getLength(); i++) {
    Element o = (Element) otos.item(i);
    if ("true".equals(o.getAttribute("constrained")) && o.getAttribute("cascade").contains("delete-orphan")) {
        throw new IllegalStateException("constrained one-to-one " + o.getAttribute("name") + " cannot use delete-orphan");
    }
}

Try / catch

catch (MappingException e) during SessionFactory build; the message names the one-to-one attribute. Remove delete-orphan from that side's cascade and move orphan-removal semantics to the FK-owning side if needed.

Prevention

When it happens

Trigger: <one-to-one name='...' constrained='true' cascade='delete-orphan'/> or cascade='all-delete-orphan' on the constrained side of a one-to-one association.

Common situations: Bidirectional one-to-one mappings where the same cascade string was copied to both sides; converting a many-to-one to one-to-one without adjusting the cascade; legacy Hibernate 3 mappings migrated forward.

Related errors


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