{"record":{"id":"af24e4f570619f31","repo":"hibernate/hibernate-orm","slug":"number-of-referencing-columns-s-did-not-match-n","errorCode":null,"errorMessage":"Number of referencing columns [%s] did not match number of referenced columns [%s] in foreign-key [%s] from [%s] to [%s]","messagePattern":"Number of referencing columns \\[(.+?)\\] did not match number of referenced columns \\[(.+?)\\] in foreign-key \\[(.+?)\\] from \\[(.+?)\\] to \\[(.+?)\\]","errorType":"exception","errorClass":"AssertionFailure","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardForeignKeyExporter.java","lineNumber":99,"sourceCode":"\t\t\tString[] targetColumnNames) {\n\t\tfinal String keyDefinition = foreignKey.getKeyDefinition();\n\t\tfinal String constraintName = quotedConstraintName( foreignKey, metadata );\n\t\treturn keyDefinition != null\n\t\t\t\t? dialect.getAddForeignKeyConstraintString( constraintName, keyDefinition )\n\t\t\t\t: dialect.getAddForeignKeyConstraintString( constraintName, columnNames,\n\t\t\t\t\t\ttargetTableName, targetColumnNames, foreignKey.isReferenceToPrimaryKey() );\n\t}\n\n\tprivate String quotedConstraintName(ForeignKey foreignKey, Metadata metadata) {\n\t\treturn metadata.getDatabase().getJdbcEnvironment().getIdentifierHelper()\n\t\t\t\t.toIdentifier( foreignKey.getName() ).render( dialect );\n\t}\n\n\tprivate static List<Column> getTargetColumns(ForeignKey foreignKey, int numberOfColumns) {\n\t\tif ( foreignKey.isReferenceToPrimaryKey() ) {\n\t\t\tfinal var primaryKey = foreignKey.getReferencedTable().getPrimaryKey();\n\t\t\tif ( numberOfColumns != primaryKey.getColumnSpan() ) {\n\t\t\t\tthrow new AssertionFailure(\n\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\tLocale.ENGLISH,\n\t\t\t\t\t\t\t\tCOLUMN_MISMATCH_MSG,\n\t\t\t\t\t\t\t\tnumberOfColumns,\n\t\t\t\t\t\t\t\tprimaryKey.getColumnSpan(),\n\t\t\t\t\t\t\t\tforeignKey.getName(),\n\t\t\t\t\t\t\t\tforeignKey.getTable().getName(),\n\t\t\t\t\t\t\t\tforeignKey.getReferencedTable().getName()\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn primaryKey.getColumns();\n\t\t}\n\t\telse {\n\t\t\tfinal var referencedColumns = foreignKey.getReferencedColumns();\n\t\t\tif ( numberOfColumns != referencedColumns.size() ) {\n\t\t\t\tthrow new AssertionFailure(\n\t\t\t\t\t\tString.format(","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardForeignKeyExporter.java#L81-L117","documentation":"When emitting foreign-key DDL for an FK that references the primary key of the target table, StandardForeignKeyExporter.getTargetColumns must pair every referencing column with a PK column. If the number of referencing columns differs from the referenced PK's column span, this AssertionFailure aborts DDL generation, reporting both counts, the FK name, and both table names. The mapping promises a different arity than the referenced key actually has.","triggerScenarios":"An association whose referencing side has fewer or more columns than the referenced @EmbeddedId/@IdClass primary key: a single @JoinColumn pointing at a two-column composite PK; a @ManyToOne to a composite-key entity without @JoinColumns covering every key column; refactoring that added a column to the PK without updating the join mapping; @OneToMany with @JoinColumn(s) on the child that do not span the parent's composite id.","commonSituations":"Composite-key entities (@EmbeddedId/@IdClass) where developers map only the 'main' join column; legacy schemas whose FK covers only part of the PK; copy-pasted associations between entities with different key shapes; schema validation/export run in CI exposing previously untested mappings.","solutions":["Match arity: for a composite referenced PK provide one @JoinColumn per PK column (wrapped in @JoinColumns), each with an explicit referencedColumnName, in the same order as the id fields.","If the FK intentionally references only part of the key, point referencedColumnName at a unique non-PK column so isReferenceToPrimaryKey() is false and the explicit referenced-columns branch is used.","Verify the referenced id mapping itself: @EmbeddedId field order / @IdClass fields must line up with the @JoinColumns order."],"exampleFix":"// before: OrderHeader has composite PK (orderId, line)\n@ManyToOne\n@JoinColumn(name = \"order_id\", referencedColumnName = \"orderId\")\nprivate OrderHeader header;\n\n// after: one entry per PK column, same order as the id mapping\n@ManyToOne\n@JoinColumns({\n    @JoinColumn(name = \"order_id\", referencedColumnName = \"orderId\"),\n    @JoinColumn(name = \"order_line\", referencedColumnName = \"line\")\n})\nprivate OrderHeader header;","handlingStrategy":"validation","validationCode":"// before export: assert join-column count equals the referenced composite PK span\nint joinCount = property.isAnnotationPresent(JoinColumns.class)\n        ? property.getAnnotation(JoinColumns.class).value().length\n        : (property.isAnnotationPresent(JoinColumn.class) ? 1 : 0);\nint pkSpan = referencedEntity.getIdColumnCount(); // from id metadata / @EmbeddedId fields\nif (joinCount != 0 && joinCount != pkSpan) {\n    throw new IllegalStateException(\"FK arity mismatch on \" + property + \": \" + joinCount + \" vs PK span \" + pkSpan);\n}","typeGuard":null,"tryCatchPattern":"try {\n    new SchemaExport(metadata).createOnly(); // or exporter call\n} catch (AssertionFailure af) {\n    if (af.getMessage() != null && af.getMessage().startsWith(\"Number of referencing columns\")) {\n        // align @JoinColumns one-per-column with the referenced primary key, rebuild metadata, retry\n    } else { throw af; }\n}","preventionTips":["Always specify referencedColumnName on every @JoinColumn that targets a composite key.","Add a CI step that exports schema to STDOUT for all entities; arity bugs surface there before runtime.","Re-audit association mappings whenever a primary key gains or loses a column."],"tags":["hibernate","foreign-key","mapping","composite-key","ddl","assertion"],"backgroundTag":"foreign-key-column-count-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}