{"record":{"id":"e3de3e8f05da6283","repo":"hibernate/hibernate-orm","slug":"association-s-is-mappedby-a-property-s-of-e3de3e","errorCode":null,"errorMessage":"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns","messagePattern":"Association '(.+?)' is 'mappedBy' a property '(.+?)' of entity '(.+?)' with multiple columns","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java","lineNumber":630,"sourceCode":"\t\t\t\t\t\t\t\tgetPropertyHolder().getPath(),\n\t\t\t\t\t\t\t\tgetMappedByPropertyName(),\n\t\t\t\t\t\t\t\tgetMappedByEntityName()\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t\tif ( !(value.getSelectables().get( 0 ) instanceof Column column) ) {\n\t\t\t\tthrow new AnnotationException(\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\t\"Association '%s' is 'mappedBy' a property '%s' of entity '%s' which maps to a formula\",\n\t\t\t\t\t\t\t\tgetPropertyHolder().getPath(),\n\t\t\t\t\t\t\t\tgetMappedByPropertyName(),\n\t\t\t\t\t\t\t\tgetPropertyHolder().getPath()\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t\tif ( value.getSelectables().size() > 1 ) {\n\t\t\t\tthrow new AnnotationException(\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\t\"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns\",\n\t\t\t\t\t\t\t\tgetPropertyHolder().getPath(),\n\t\t\t\t\t\t\t\tgetMappedByPropertyName(),\n\t\t\t\t\t\t\t\tgetPropertyHolder().getPath()\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn column.getNameIdentifier( getBuildingContext() );\n\t\t}\n\n\t\t@Override\n\t\tpublic MetadataBuildingContext getBuildingContext() {\n\t\t\treturn AnnotatedJoinColumns.this.getBuildingContext();\n\t\t}\n\t}\n","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java#L612-L648","documentation":"The property this association is 'mappedBy' maps to MULTIPLE columns (a composite value: multi-column type, embeddable, or composite FK). Deriving the inverse side's single default join/order column requires exactly one column, so Hibernate rejects it. (The message prints the holder path twice due to an upstream formatting quirk — the third %s should be the entity name.)","triggerScenarios":"'@OneToMany(mappedBy = \"x\")' where x is a @ManyToOne with a composite key (@JoinColumns with 2+ columns, or a composite @EmbeddedId target); the owning side maps an embeddable with several @Columns; mappedBy points at a property whose value.getSelectables().size() > 1.","commonSituations":"Composite primary keys in legacy schemas; trying to add an inverse collection to an association whose FK spans two columns; aggregating columns into one property via a custom composite user type.","solutions":["Map the collection WITHOUT relying on the derived single column: use an explicit @JoinTable, or leave the association unidirectional from the owning side.","Simplify the owning side to a single-column @JoinColumn if the schema permits.","For composite FKs with @MapsId-style derived ids, mirror each column explicitly instead of using mappedBy."],"exampleFix":"// before\n@Entity\nclass Invoice {\n    // composite FK: order_id + line_no\n    @ManyToOne\n    @JoinColumns({@JoinColumn(name = \"order_id\"), @JoinColumn(name = \"line_no\")})\n    OrderLine line;\n}\n\n@Entity\nclass OrderLine {\n    @OneToMany(mappedBy = \"line\") // -> error: multiple columns\n    List<Invoice> invoices;\n}\n\n// after\n@Entity\nclass OrderLine {\n    @OneToMany\n    @JoinTable(name = \"line_invoices\",\n        joinColumns = {@JoinColumn(name = \"order_id\"), @JoinColumn(name = \"line_no\")},\n        inverseJoinColumns = @JoinColumn(name = \"invoice_id\"))\n    List<Invoice> invoices;\n}","handlingStrategy":"validation","validationCode":"// Guard: mappedBy owner must map exactly one column\nString mappedBy = \"line\";\nField owner = Invoice.class.getDeclaredField(mappedBy);\nJoinColumns jcs = owner.getAnnotation(JoinColumns.class);\nint n = jcs == null\n    ? (owner.getAnnotation(JoinColumn.class) != null ? 1 : 0)\n    : jcs.value().length;\nif (n > 1) throw new IllegalStateException(\n    \"mappedBy '\" + mappedBy + \"' maps \" + n + \" columns; use a @JoinTable instead\");","typeGuard":null,"tryCatchPattern":"try {\n    factory = cfg.buildSessionFactory();\n} catch (AnnotationException e) {\n    // 'with multiple columns' -> map the collection with an explicit\n    // @JoinTable listing every composite column\n    throw newConfigurationException(\"Composite mappedBy owner\", e);\n}","preventionTips":["With composite FKs, prefer unidirectional mappings or explicit @JoinTable/@JoinColumns on the collection.","Never assume mappedBy works over embeddables or multi-column types."],"tags":["hibernate","jpa","mappedby","composite-key","orm-mapping"],"backgroundTag":"mappedby-misuse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}