hibernate/hibernate-orm · error · IllegalArgumentException

A CTE object with the name

Error message

A CTE object with the name {} already exists

What it means

The CteObject counterpart of the duplicate-label check: addCteObject registers CTE objects (Hibernate 7's modifiable/mutation CTE objects) by name with putIfAbsent and throws IllegalArgumentException if an object with the same name is already registered in the same CTE scope.

Solutions

  1. Give each CTE object a unique name within the statement
  2. When composing statements from fragments, prefix object names with a scope or counter
  3. Reuse the existing CteObject instead of registering a second one under the same name

Example fix

// before
container.addCteObject(new CteObject("changes", ...));
container.addCteObject(new CteObject("changes", ...));

// after
container.addCteObject(new CteObject("changes_1", ...));
container.addCteObject(new CteObject("changes_2", ...));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> names = container.getCteObjects().keySet();
if (names.contains(cteObject.getName())) {
    throw new IllegalArgumentException("CTE object '" + cteObject.getName() + "' already exists");
}
container.addCteObject(cteObject);

Try / catch

try {
    session.createQuery(hql).executeUpdate();
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("CTE object")) {
        log.error("Duplicate CTE object name in: {}", hql);
    }
    throw e;
}

Prevention

When it happens

Trigger: Programmatically registering two CteObject instances with the same name on one statement; HQL or criteria using the new modifiable-CTE feature ('with ... update/delete ... returning') twice under one name; merging containers that both carry a same-named CTE object.

Common situations: Adopting Hibernate 7 CTE objects for insert/update returning-style flows; name templates that collide when a statement is composed from repeated fragments.

Related errors


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

Appendix: source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java:9516

		}

		@Override
		public Map<String, CteObject> getCteObjects() {
			return cteObjects;
		}

		@Override
		public CteObject getCteObject(String cteObjectName) {
			final var cteObject = cteObjects.get( cteObjectName );
			return cteObject == null && parent != null
					? parent.getCteObject( cteObjectName )
					: cteObject;
		}

		@Override
		public void addCteObject(CteObject cteObject) {
			if ( cteObjects.putIfAbsent( cteObject.getName(), cteObject ) != null ) {
				throw new IllegalArgumentException( "A CTE object with the name " + cteObject.getName() + " already exists" );
			}
		}
	}

	@Override
	public boolean registerVisitedAssociationKey(AssociationKey associationKey) {
		return visitedAssociationKeys.add( associationKey );
	}

	@Override
	public void removeVisitedAssociationKey(AssociationKey associationKey) {
		visitedAssociationKeys.remove( associationKey );
	}

	@Override
	public boolean isAssociationKeyVisited(AssociationKey associationKey) {
		return visitedAssociationKeys.contains( associationKey );
	}

View on GitHub (pinned to fad1729dce)