{"record":{"id":"797141e7af9c7e4d","repo":"hibernate/hibernate-orm","slug":"missing-unique-constraint-named-s-on-table-s","errorCode":null,"errorMessage":"Missing unique constraint named `%s` on table `%s`","messagePattern":"Missing unique constraint named `(.+?)` on table `(.+?)`","errorType":"exception","errorClass":"SchemaManagementException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java","lineNumber":270,"sourceCode":"\t\t\tassert StringHelper.isNotEmpty( rawName );\n\t\t\tassert Objects.equals( rawName, uk.getName() );\n\t\t\tif ( validationType == ConstraintValidationType.NONE ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if ( validationType == ConstraintValidationType.NAMED ) {\n\t\t\t\tif ( rawName.startsWith( \"UK\" ) ) {\n\t\t\t\t\t// this is not a great check as the user could very well\n\t\t\t\t\t// have explicitly chosen a name that starts with this as well,\n\t\t\t\t\t// but...\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar name = metadata.getDatabase().toIdentifier( rawName );\n\t\t\tfinal IndexInformation ukInfo = tableInformation.getIndex( name );\n\n\t\t\tif ( ukInfo == null ) {\n\t\t\t\tthrow new SchemaManagementException(\n\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\tROOT,\n\t\t\t\t\t\t\t\t\"Missing unique constraint named `%s` on table `%s`\",\n\t\t\t\t\t\t\t\tname.render( dialect ),\n\t\t\t\t\t\t\t\ttableInformation.getName().render()\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tvar matches = true;\n\t\t\tassert uk.getColumns().size() == uk.getColumnSpan();\n\t\t\tif ( uk.getColumnSpan() != ukInfo.getIndexedColumns().size() ) {\n\t\t\t\tmatches = false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor ( int i = 0; i < uk.getColumns().size(); i++ ) {\n\t\t\t\t\tfinal Column column = uk.getColumns().get( i );\n\t\t\t\t\tfinal ColumnInformation columnInfo = ukInfo.getIndexedColumns().get( i );","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java#L252-L288","documentation":"Unique-constraint validation: the mapping declares a unique key with an explicit name, and the validator looks it up via tableInformation.getIndex(name) - Hibernate validates unique keys as indexes in JDBC metadata. If no index/constraint with that exact name exists on the table, validation fails. Only applies when hibernate.tooling.schema.unique_key_validation is NAMED (skips generated 'UK'-prefixed names) or ALL.","triggerScenarios":"validate with hibernate.tooling.schema.unique_key_validation=NAMED/ALL and a named @Table(uniqueConstraints = @UniqueConstraint(name = \"uk_...\", columnNames = ...)), while the database enforces uniqueness under a different name: PostgreSQL auto-generated names like customer_email_key, MySQL unique keys recorded with table-prefixed names, or the constraint created by an old migration with its own naming scheme.","commonSituations":"Explicit constraint names added to mappings later than the schema; databases that ignore custom constraint names at creation time; legacy schemas where uniqueness is enforced by a manually created unique index rather than a named constraint.","solutions":["Recreate the constraint with the declared name: ALTER TABLE ... DROP CONSTRAINT <existing>; ALTER TABLE ... ADD CONSTRAINT uk_... UNIQUE (...);","Or change @UniqueConstraint(name=...) to the constraint name that actually exists.","If uniqueness is migration-managed only, drop the name (or the declaration) or set hibernate.tooling.schema.unique_key_validation=NONE."],"exampleFix":"-- before: uniqueness exists but under a PostgreSQL-generated name (customer_email_key)\nALTER TABLE customer DROP CONSTRAINT customer_email_key;\n\n-- after: constraint recreated under the name the mapping validates\nALTER TABLE customer ADD CONSTRAINT uk_customer_email UNIQUE (email);","handlingStrategy":"validation","validationCode":"// Before validate with unique_key_validation=NAMED/ALL, confirm each named constraint exists\ntry (Connection c = dataSource.getConnection()) {\n    try (ResultSet rs = c.getMetaData().getIndexInfo(null, null, \"customer\", false, true)) {\n        boolean found = false;\n        while (rs.next()) {\n            if (\"uk_customer_email\".equalsIgnoreCase(rs.getString(\"INDEX_NAME\"))) found = true;\n        }\n        if (!found) {\n            throw new IllegalStateException(\"uk_customer_email missing - add it via migration before validate\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new SchemaValidator().validate(metadata, serviceRegistry);\n} catch (SchemaManagementException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Missing unique constraint\")) {\n        // add the constraint with the declared name or rename the @UniqueConstraint to the existing one\n    }\n    throw e;\n}","preventionTips":["Always name @UniqueConstraint explicitly and create it with that exact name in the migration","Avoid database-generated constraint names on schema Hibernate validates","Enable unique_key_validation in CI once constraints and mappings are aligned"],"tags":["hibernate","schema-validation","unique-constraint","hbm2ddl","ddl-migration"],"backgroundTag":"missing-unique-constraint","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}