hibernate/hibernate-orm · error · MappingException

UniqueKey {} already exists

Error message

UniqueKey {} already exists

What it means

Table.addUniqueKey(UniqueKey) mirrors addIndex: it registers a unique constraint by name on a table and throws when a UniqueKey with that name already exists in uniqueKeys. Unique constraint names share the database namespace per table/schema, so Hibernate refuses silent overwriting and reports the colliding name.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/mapping/Table.java:478

	}

	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!
	 */
	public void createUniqueKey(Column column, MetadataBuildingContext context) {
		final String keyName = context.getBuildingOptions().getImplicitNamingStrategy()
				.determineUniqueKeyName( new ImplicitUniqueKeyNameSource() {
					@Override
					public Identifier getTableName() {
						return name;
					}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Locate all @UniqueConstraint (and <unique-key>) declarations for the table and give each a distinct, descriptive name like uk_orders_order_number.
  2. Remove redundant duplicates that constrain the same column set.
  3. For programmatic mapping, check uniqueKeys.get(name) (or table.getUniqueKey(name)) before adding.
  4. Use a consistent naming scheme including the table name to avoid cross-subclass collisions.

Example fix

// before
@Table(name = "users", uniqueConstraints = {
    @UniqueConstraint(name = "uk_email", columnNames = "email")
})
public class User { ... }
@AttributeOverrides... // subclass adds uk_email again to same table

// after — one constraint only, clearly named
@Table(name = "users", uniqueConstraints = {
    @UniqueConstraint(name = "uk_users_email", columnNames = "email")
})
public class User { ... }
Defensive patterns

Strategy: validation

Validate before calling

// programmatic mapping: check before add
if (table.getUniqueKey("uk_users_email") != null) {
    // constraint already registered — skip or rename
} else {
    table.addUniqueKey(uk);
}

Try / catch

try {
    metadata.buildMetadata().validate();
} catch (MappingException e) {
    if (e.getMessage().matches("UniqueKey .+ already exists")) {
        // duplicate @UniqueConstraint/<unique-key> name — dedupe
    }
    throw e;
}

Prevention

When it happens

Trigger: Two @UniqueConstraint(name = "uk_x", columnNames = {...}) entries resolving to the same table name; @Table(uniqueConstraints = ...) duplicated across SINGLE_TABLE subclasses that share one physical table; hbm.xml <unique-key name="x"/> declared twice for one table; programmatic table.addUniqueKey(...) called twice with the same name.

Common situations: Inheritance hierarchies where each subclass adds the same named constraint to the shared root table; refactors that moved @UniqueConstraint between class-level and property-level annotations leaving duplicates; merging XML mappings; DDL-generation tests after annotations were copy-pasted between related entities.

Related errors


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