hibernate/hibernate-orm · error · MappingException
Index {} already exists
Error message
Index {} already exists What it means
Table.addIndex(Index) rejects registering a second index with the same name on one table. Index names must be unique per table (and in most databases per schema), so when the mapping layer or programmatic API tries to add an index whose name already exists in the table's index map, Hibernate throws this MappingException with the duplicated name.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/mapping/Table.java:469
return index;
}
else {
final var newIndex = new Index();
newIndex.setName( indexName );
newIndex.setTable( this );
indexes.put( indexName, newIndex );
return newIndex;
}
}
public Index getIndex(String indexName) {
return indexes.get( indexName );
}
public Index addIndex(Index index) {
final var current = indexes.get( index.getName() );
if ( current != null ) {
throw new MappingException( "Index " + index.getName() + " already exists" );
}
indexes.put( index.getName(), index );
return index;
}
public UniqueKey addUniqueKey(UniqueKey uniqueKey) {
final var current = uniqueKeys.get( uniqueKey.getName() );
if ( current != null ) {
throw new MappingException( "UniqueKey " + uniqueKey.getName() + " already exists" );
}
uniqueKeys.put( uniqueKey.getName(), uniqueKey );
return uniqueKey;
}
/**
* Mark the given column unique and assign a name to the unique key.
* <p>
* This method does not add a {@link UniqueKey} to the table itself!View on GitHub (pinned to fad1729dce)
Solutions
- Search all entities and hbm files mapping the table named in the message for the index name, and make each @Index name unique (e.g. prefix with table name: idx_orders_custid).
- If the duplication is intentional (same columns), keep exactly one declaration and delete the redundant one.
- In programmatic models, guard with table.getIndex(name) != null before table.addIndex(index).
- Adopt a naming convention (table_column_purpose) so hand-written index names cannot collide.
Example fix
// before
@Table(name = "orders", indexes = @Index(name = "idx_cust", columnList = "customer_id"))
public class Order { ... }
@Index(name = "idx_cust", columnList = "customer_email") // duplicate name, same table
private String email;
// after
@Index(name = "idx_orders_email", columnList = "customer_email")
private String email; Defensive patterns
Strategy: validation
Validate before calling
// programmatic mapping: check before add
if (table.getIndex("idx_orders_cust") != null) {
// reuse existing index or pick another name
} else {
table.addIndex(newIndex);
} Try / catch
try {
metadata.buildMetadata().validate();
} catch (MappingException e) {
if (e.getMessage().matches("Index .+ already exists")) {
// duplicate @Index/<index> name on one table — dedupe names
}
throw e;
} Prevention
- Name indexes <table>_<column(s)>_<purpose> to guarantee uniqueness.
- For SINGLE_TABLE hierarchies, declare indexes once on the root entity.
- Lint annotations in CI: collect @Index names per table and assert uniqueness.
When it happens
Trigger: Two @Index(name = "idx_x", columnList = "...") annotations resolving to the same table with the same name; hbm.xml <index name="x"/> appearing twice for one table; @Table(indexes = ...) plus an entity-level @Index with the same name; programmatic mapping calling table.addIndex(...) twice with equal names.
Common situations: Copy-pasted index annotations across entities mapped to one table (e.g. @Inheritance SINGLE_TABLE subclasses each adding indexes on the shared table); combining @Table(indexes=...) with a second redundant annotation after refactoring; XML and annotation sources merged for one table; schema-generation pipelines that union indexes from several mapping files.
Related errors
- UniqueKey {} already exists
- SingleStore does not support dropping creating/dropping sche
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
- One to many association '<propertyName>' was annotated '@Col
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/06c9c2d34832c606.
Report an issue: GitHub.