{"record":{"id":"78fa4017d1cd9a6e","repo":"hibernate/hibernate-orm","slug":"foreign-key-must-have-same-number-of","errorCode":null,"errorMessage":"Foreign key ({}:{} [{}])) must have same number of columns as the referenced primary key ({} [{}])","messagePattern":"Foreign key \\((.+?):(.+?) \\[(.+?)\\]\\)\\) must have same number of columns as the referenced primary key \\((.+?) \\[(.+?)\\]\\)","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java","lineNumber":88,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\n\tpublic void setReferencedTable(Table referencedTable) throws MappingException {\n\t\tthis.referencedTable = referencedTable;\n\t}\n\n\t/**\n\t * Validates that column span of the foreign key and the primary key is the same.\n\t * <p>\n\t * Furthermore it aligns the length of the underlying tables columns.\n\t */\n\tpublic void alignColumns() {\n\t\tif ( isReferenceToPrimaryKey() ) {\n\t\t\tfinal int columnSpan = getColumnSpan();\n\t\t\tfinal var primaryKey = referencedTable.getPrimaryKey();\n\t\t\tif ( primaryKey.getColumnSpan() != columnSpan ) {\n\t\t\t\tthrow new MappingException( unalignedColumnsMessage( primaryKey ) );\n\t\t\t}\n\n\t\t\t//TODO: shouldn't this happen even for non-PK references?\n\t\t\tfor ( int i = 0; i<columnSpan; i++ ) {\n\t\t\t\tfinal var referencedColumn = primaryKey.getColumn(i);\n\t\t\t\tfinal var referencingColumn = getColumn(i);\n\t\t\t\treferencingColumn.setLength( referencedColumn.getLength() );\n\t\t\t\treferencingColumn.setScale( referencedColumn.getScale() );\n\t\t\t\treferencingColumn.setPrecision( referencedColumn.getPrecision() );\n\t\t\t\treferencingColumn.setArrayLength( referencedColumn.getArrayLength() );\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String unalignedColumnsMessage(PrimaryKey primaryKey) {\n\t\tfinal var message = new StringBuilder();\n\t\tmessage.append( \"Foreign key (\" ).append( getName() ).append( \":\" )\n\t\t\t\t.append( getTable().getName() )","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java#L70-L106","documentation":"ForeignKey#alignColumns validates that a foreign key referencing the target primary key has exactly as many columns as that PK. A mismatch means the composite join does not line up with the referenced composite key, so Hibernate aborts before generating a broken FK, while also using the check to align column length/scale/precision.","triggerScenarios":"The target has a composite @EmbeddedId while the referencing side declares fewer @JoinColumn entries; the parent PK gained a column but child mappings were not updated; @JoinColumn entries referencing only part of the composite PK; column ordering changed inside @Embeddable.","commonSituations":"Evolving composite keys; hand-written @JoinColumn(name=...) without referencedColumnName; switching between @IdClass and @EmbeddedId; database refactors adding PK columns.","solutions":["Declare one @JoinColumn per referenced PK column, each with an explicit referencedColumnName matching the PK column names.","If the parent PK changed, update every child mapping's join columns in the same change.","Check for accidentally duplicated or missing @JoinColumn annotations and align their order with the PK."],"exampleFix":"// before - parent PK is composite (a, b)\n@Id\n@ManyToOne\n@JoinColumn(name = \"a\")\nprivate Parent parent;\n\n// after\n@Id\n@ManyToOne\n@JoinColumns({\n    @JoinColumn(name = \"a\", referencedColumnName = \"a\"),\n    @JoinColumn(name = \"b\", referencedColumnName = \"b\")\n})\nprivate Parent parent;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    metadata = sources.buildMetadata();\n} catch (MappingException e) {\n    // message prints both key column lists - diff them to find the\n    // missing or extra join column on the referencing side\n    throw e;\n}","preventionTips":["For composite PKs always use @JoinColumns with explicit referencedColumnName - never rely on defaults.","When adding a PK column, grep mappings for associations to that entity and update the join columns.","Run SchemaValidator or create-drop in CI to catch FK span mismatches before deployment."],"tags":["hibernate","orm","mapping","foreign-key","composite-key","join-columns"],"backgroundTag":"foreign-key-column-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}