{"record":{"id":"7ea8cbcc311d5426","repo":"hibernate/hibernate-orm","slug":"duplicate-identifier-in-table-s-s-s","errorCode":null,"errorMessage":"Duplicate identifier in table (%s) - %s#%s","messagePattern":"Duplicate identifier in table \\((.+?)\\) - (.+?)#(.+?)","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/action/queue/spi/bind/Checkers.java","lineNumber":53,"sourceCode":"\t\t\texpectation.verifyOutcome(\n\t\t\t\t\taffectedRowCount,\n\t\t\t\t\tnull,\n\t\t\t\t\tbatchPosition,\n\t\t\t\t\tsqlString\n\t\t\t);\n\t\t}\n\t\tcatch (StaleStateException e) {\n\t\t\tif ( !mutatingTable.isOptional() && affectedRowCount == 0 ) {\n\t\t\t\tfinal StatisticsImplementor statistics = sessionFactory.getStatistics();\n\t\t\t\tif ( statistics.isStatisticsEnabled() ) {\n\t\t\t\t\tstatistics.optimisticFailure( mutationTarget.getNavigableRole().getFullPath() );\n\t\t\t\t}\n\t\t\t\tthrow new StaleObjectStateException( mutationTarget.getNavigableRole().getFullPath(), id, e );\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tcatch (TooManyRowsAffectedException e) {\n\t\t\tthrow new HibernateException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Duplicate identifier in table (%s) - %s#%s\",\n\t\t\t\t\t\t\tmutatingTable.name(),\n\t\t\t\t\t\t\tmutationTarget.getNavigableRole().getFullPath(),\n\t\t\t\t\t\t\tid\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","sourceCodeStart":35,"sourceCodeEnd":70,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/action/queue/spi/bind/Checkers.java#L35-L70","documentation":"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)'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Locate duplicates with SELECT id, COUNT(*) FROM <table> GROUP BY id HAVING COUNT(*) > 1, delete the extras, then re-add the primary key constraint.","On SQL Server, ensure triggers on the table issue SET NOCOUNT ON so the true affected count reaches the driver.","Verify the mutation target's join/key column mapping matches the actual schema - a wrong column can match multiple rows."],"exampleFix":"-- before: no PK enforced, duplicates exist\nSELECT order_id, COUNT(*) FROM order_lines GROUP BY order_id HAVING COUNT(*) > 1;\n-- fix data, then enforce the key\nDELETE FROM order_lines WHERE ctid NOT IN (SELECT MIN(ctid) FROM order_lines GROUP BY order_id);\nALTER TABLE order_lines ADD PRIMARY KEY (order_id);","handlingStrategy":"validation","validationCode":"// health check: detect duplicate ids before Hibernate does\nList<Object[]> dupes = em.createNativeQuery(\n    \"select id, count(*) from order_lines group by id having count(*) > 1\")\n    .getResultList();\nif (!dupes.isEmpty()) throw new IllegalStateException(\"duplicate rows: \" + dupes);","typeGuard":null,"tryCatchPattern":"try {\n    session.flush();\n}\ncatch (HibernateException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Duplicate identifier in table\")) {\n        // quarantine and repair the duplicated rows, then retry the transaction\n    }\n    else throw e;\n}","preventionTips":["Always enforce primary key constraints on mutation tables, including secondary/joined tables","Set SET NOCOUNT ON in SQL Server triggers so affected-row counts stay accurate","Validate bulk imports for id uniqueness before they reach production tables"],"tags":["hibernate","data-integrity","duplicate-key","sql-server-triggers"],"backgroundTag":"duplicate-primary-key","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}