hibernate/hibernate-orm · error · UnsupportedOperationException

queued clear cannot be used with orphan delete

Error message

queued clear cannot be used with orphan delete

What it means

PersistentList queues operations on an uninitialized lazy collection, so clear() on an uninitialized list becomes a queued Clear operation instead of running immediately. Because a bulk Clear cannot know which individual elements were removed, its getOrphan() throws UnsupportedOperationException when Hibernate needs per-element orphan information — which happens when the association has orphan delete enabled (orphanRemoval=true / delete-orphan) at flush time.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentList.java:664

	@Override
	public boolean entryExists(Object entry, int i) {
		return entry!=null;
	}

	final class Clear implements DelayedOperation<E> {
		@Override
		public void operate() {
			list.clear();
		}

		@Override
		public E getAddedInstance() {
			return null;
		}

		@Override
		public E getOrphan() {
			throw new UnsupportedOperationException( "queued clear cannot be used with orphan delete" );
		}
	}

	protected final class SimpleAdd extends AbstractValueDelayedOperation {

		public SimpleAdd(E addedValue) {
			super( addedValue, null );
		}

		@Override
		public void operate() {
			list.add( getAddedInstance() );
		}
	}

	abstract class AbstractListValueDelayedOperation extends AbstractValueDelayedOperation {
		private final int index;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Force initialization before clearing: call Hibernate.initialize(parent.getChildren()) or touch size() first, so clear() executes directly and orphans are computed from the snapshot
  2. Remove elements individually on the initialized collection (iterator.remove()/removeIf) so each removal carries its own orphan
  3. Reconsider orphanRemoval=true for associations whose normal use is full clear-and-replace
  4. Add an integration test that runs the clear+flush flow against the real mapping

Example fix

// before
parent.getChildren().clear();   // uninitialized -> queued Clear
parent.getChildren().addAll(newKids);
tx.commit();                    // flush -> UnsupportedOperationException

// after
Hibernate.initialize(parent.getChildren()); // force init
parent.getChildren().clear();               // direct clear, orphans tracked
parent.getChildren().addAll(newKids);
Defensive patterns

Strategy: validation

Validate before calling

List<Item> children = parent.getChildren();
if (children instanceof org.hibernate.collection.spi.PersistentCollection pc && !pc.wasInitialized()) {
    org.hibernate.Hibernate.initialize(children); // force init so clear() is not queued
}
children.clear();

Try / catch

try {
    tx.commit();
} catch (org.hibernate.HibernateException e) {
    if (e instanceof java.util.UnsupportedOperationException
            || e.getCause() instanceof java.util.UnsupportedOperationException uoe
            && String.valueOf(uoe.getMessage()).contains("queued clear")) {
        throw new IllegalStateException("clear() on an uninitialized collection with orphanRemoval is not supported; initialize the collection first", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: @OneToMany(cascade = ALL, orphanRemoval = true) List<Item> children; the parent is loaded without touching children; code calls parent.getChildren().clear() (typical 'replace all children' pattern); at flush the collection role requires orphan deletion and calls getOrphan() on the queued Clear.

Common situations: Replace-children flows (clear() + addAll()) on lazy collections; entity copy/merge utilities that clear target collections; switching a mapping from EAGER to LAZY making the collection uninitialized where clear() used to run directly; upgrading Hibernate versions where queueing behavior changed.

Related errors


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