hibernate/hibernate-orm · error · IllegalArgumentException

A CTE object with the name {} already exists

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.

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)

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.