hibernate/hibernate-orm · error · HibernateException

Duplicate identifier in table (%s) - %s#%s

Error message

Duplicate identifier in table (%s) - %s#%s

What it means

A mutation against an identified table reported more affected rows than the expectation permits (TooManyRowsAffectedException caught in Checkers.identifiedResultsCheck). Because the statement targets rows by primary key, more than one affected row means the table physically contains duplicate rows for the same identifier - a data-integrity violation surfaced as 'Duplicate identifier in table (... - entity#id)'.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/spi/bind/Checkers.java:53

			expectation.verifyOutcome(
					affectedRowCount,
					null,
					batchPosition,
					sqlString
			);
		}
		catch (StaleStateException e) {
			if ( !mutatingTable.isOptional() && affectedRowCount == 0 ) {
				final StatisticsImplementor statistics = sessionFactory.getStatistics();
				if ( statistics.isStatisticsEnabled() ) {
					statistics.optimisticFailure( mutationTarget.getNavigableRole().getFullPath() );
				}
				throw new StaleObjectStateException( mutationTarget.getNavigableRole().getFullPath(), id, e );
			}
			return false;
		}
		catch (TooManyRowsAffectedException e) {
			throw new HibernateException(
					String.format(
							Locale.ROOT,
							"Duplicate identifier in table (%s) - %s#%s",
							mutatingTable.name(),
							mutationTarget.getNavigableRole().getFullPath(),
							id
					)
			);
		}
		catch (Throwable t) {
			return false;
		}

		return true;
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Locate duplicates with SELECT id, COUNT(*) FROM <table> GROUP BY id HAVING COUNT(*) > 1, delete the extras, then re-add the primary key constraint.
  2. On SQL Server, ensure triggers on the table issue SET NOCOUNT ON so the true affected count reaches the driver.
  3. Verify the mutation target's join/key column mapping matches the actual schema - a wrong column can match multiple rows.

Example fix

-- before: no PK enforced, duplicates exist
SELECT order_id, COUNT(*) FROM order_lines GROUP BY order_id HAVING COUNT(*) > 1;
-- fix data, then enforce the key
DELETE FROM order_lines WHERE ctid NOT IN (SELECT MIN(ctid) FROM order_lines GROUP BY order_id);
ALTER TABLE order_lines ADD PRIMARY KEY (order_id);
Defensive patterns

Strategy: validation

Validate before calling

// health check: detect duplicate ids before Hibernate does
List<Object[]> dupes = em.createNativeQuery(
    "select id, count(*) from order_lines group by id having count(*) > 1")
    .getResultList();
if (!dupes.isEmpty()) throw new IllegalStateException("duplicate rows: " + dupes);

Try / catch

try {
    session.flush();
}
catch (HibernateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Duplicate identifier in table")) {
        // quarantine and repair the duplicated rows, then retry the transaction
    }
    else throw e;
}

Prevention

When it happens

Trigger: UPDATE/DELETE ... WHERE id = ? affecting 2+ rows: duplicate PK rows in the table because the primary key constraint is missing or was dropped; or a SQL Server trigger altering the reported affected-row count.

Common situations: Joined-inheritance/secondary tables populated by hand or by a buggy migration without PK enforcement; SQL Server triggers missing SET NOCOUNT ON so the driver double-counts; imports that duplicated rows.

Related errors


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