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

PersistentSet queues operations on an uninitialized lazy collection, so clear() on an uninitialized set becomes a queued Clear operation. A bulk Clear cannot enumerate removed elements, so when the association has orphan delete enabled (orphanRemoval=true / delete-orphan) and flush asks the queued operation for its orphan via getOrphan(), it throws UnsupportedOperationException. Set flavor of the same limitation as PersistentList/PersistentMap.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentSet.java:460

	@Override
	public boolean isWrapper(Object collection) {
		return set==collection;
	}

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

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

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

	final class SimpleAdd extends AbstractValueDelayedOperation {

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

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

	final class SimpleRemove extends AbstractValueDelayedOperation {

		public SimpleRemove(E orphan) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Initialize before clearing: Hibernate.initialize(parent.getTags()) or call size() first
  2. Clear by individual removal on the initialized set (removeIf/iterator) so orphans are tracked per element
  3. Drop orphanRemoval=true where clear-all is the normal write pattern
  4. Test the replace-all flow end-to-end including flush

Example fix

// before
parent.getTags().clear();      // uninitialized PersistentSet -> queued Clear
parent.getTags().addAll(newTags);
tx.commit();                   // flush -> UnsupportedOperationException

// after
Hibernate.initialize(parent.getTags());
parent.getTags().clear();
parent.getTags().addAll(newTags);
Defensive patterns

Strategy: validation

Validate before calling

Set<Tag> tags = parent.getTags();
if (tags instanceof org.hibernate.collection.spi.PersistentCollection pc && !pc.wasInitialized()) {
    org.hibernate.Hibernate.initialize(tags);
}
tags.clear();

Try / catch

try {
    tx.commit();
} catch (org.hibernate.HibernateException e) {
    Throwable c = e;
    while (c != null) {
        if (c instanceof UnsupportedOperationException && String.valueOf(c.getMessage()).contains("queued clear")) {
            throw new IllegalStateException("clear() on uninitialized set with orphanRemoval; initialize first", e);
        }
        c = c.getCause();
    }
    throw e;
}

Prevention

When it happens

Trigger: @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) Set<Tag> tags; parent loaded without touching tags; tags.clear() called (e.g. replacing all tags); flush needs orphan deletion.

Common situations: Tag/role replacement flows that clear the whole set and re-add; EAGER->LAZY mapping changes; bulk edit screens saving empty sets; upgrading Hibernate where the queued path becomes reachable.

Related errors


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