{"record":{"id":"0f8b1d034f05f8b3","repo":"hibernate/hibernate-orm","slug":"property-is-annotated-both-onetomany-and","errorCode":null,"errorMessage":"Property '{}' is annotated both '@OneToMany' and '@ManyToMany'","messagePattern":"Property '(.+?)' is annotated both '@OneToMany' and '@ManyToMany'","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java","lineNumber":500,"sourceCode":"\t\t\t\tentityBinder.getSecondaryTables(),\n\t\t\t\tcontext\n\t\t);\n\t}\n\n\tprivate static String handleTargetEntity(\n\t\t\tPropertyHolder propertyHolder,\n\t\t\tPropertyData inferredData,\n\t\t\tMetadataBuildingContext context,\n\t\t\tMemberDetails property,\n\t\t\tAnnotatedJoinColumns joinColumns,\n\t\t\tOneToMany oneToManyAnn,\n\t\t\tManyToMany manyToManyAnn,\n\t\t\tElementCollection elementCollectionAnn,\n\t\t\tCollectionBinder collectionBinder) {\n\n\t\t//TODO enhance exception with @ManyToAny and @CollectionOfElements\n\t\tif ( oneToManyAnn != null && manyToManyAnn != null ) {\n\t\t\tthrow new AnnotationException( \"Property '\" + getPath( propertyHolder, inferredData )\n\t\t\t\t\t+ \"' is annotated both '@OneToMany' and '@ManyToMany'\" );\n\t\t}\n\t\tfinal String mappedBy;\n\t\tif ( oneToManyAnn != null ) {\n\t\t\tif ( joinColumns.isSecondary() ) {\n\t\t\t\tthrow new AnnotationException( \"Collection '\" + getPath( propertyHolder, inferredData )\n\t\t\t\t\t\t+ \"' has foreign key in secondary table\" );\n\t\t\t}\n\t\t\tcollectionBinder.setFkJoinColumns( joinColumns );\n\t\t\tmappedBy = nullIfEmpty( oneToManyAnn.mappedBy() );\n\t\t\tcollectionBinder.setTargetEntity( oneToManyAnn.targetEntity() );\n\t\t\tcollectionBinder.setCascadeStrategy(\n\t\t\t\t\taggregateCascadeTypes( oneToManyAnn.cascade(), property,\n\t\t\t\t\t\t\toneToManyAnn.orphanRemoval(), context ) );\n\t\t\tcollectionBinder.setOrphanRemoval( oneToManyAnn.orphanRemoval() );\n\t\t\tcollectionBinder.setOneToMany( true );\n\t\t}\n\t\telse if ( elementCollectionAnn != null ) {","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java#L482-L518","documentation":"A single property cannot be mapped as both @OneToMany and @ManyToMany; the two annotations define different relation shapes. CollectionBinder rejects the combination at the very start of collection binding, before any further processing happens.","triggerScenarios":"The same field or getter carries both @OneToMany and @ManyToMany, so oneToManyAnn != null && manyToManyAnn != null in the binding routine.","commonSituations":"IDE auto-complete or auto-import inserting the wrong annotation alongside the right one; refactoring a unidirectional one-to-many into a many-to-many and forgetting to delete the old annotation; copy-paste between properties.","solutions":["Keep exactly one of @OneToMany / @ManyToMany on the property and delete the other","If the design genuinely needs both shapes, split into two distinct properties with separate mappings","Check for stale annotations from refactoring sessions, including on getters vs fields (mixed access can hide the duplicate)"],"exampleFix":"// before\n@OneToMany(mappedBy = \"order\")\n@ManyToMany                       // error: both present\nList<Tag> tags;\n\n// after\n@OneToMany(mappedBy = \"order\")\nList<Tag> tags;","handlingStrategy":"validation","validationCode":"// Reject fields carrying both @OneToMany and @ManyToMany\nstatic void checkSingleCollectionAnnotation(Class<?>... entities) {\n    for ( Class<?> c : entities ) {\n        for ( Field f : c.getDeclaredFields() ) {\n            if ( f.isAnnotationPresent( OneToMany.class )\n                    && f.isAnnotationPresent( ManyToMany.class ) ) {\n                throw new IllegalStateException( \"Both @OneToMany and @ManyToMany on \"\n                    + c.getName() + \".\" + f.getName() );\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After changing a relation's cardinality, delete the replaced annotation immediately","Beware of annotations split across field and getter - check both access paths","Use IDE annotation-usage search for @OneToMany and @ManyToMany overlaps during reviews"],"tags":["hibernate","jpa","one-to-many","many-to-many","conflicting-annotations","annotation-binding"],"backgroundTag":"conflicting-collection-annotations","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}