{"record":{"id":"d7db4ac043a3b13e","repo":"hibernate/hibernate-orm","slug":"error-transforming-many-to-many","errorCode":null,"errorMessage":"Error transforming many-to-many : ","messagePattern":"Error transforming many-to-many : ","errorType":"exception","errorClass":"TransformationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java","lineNumber":2231,"sourceCode":"\t\t\t\telse if ( hbmCollection.getOneToMany() != null ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tattributes.getOneToManyAttributes().add( transformOneToMany( hbmCollection, propertyInfo ) );\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Exception e) {\n\t\t\t\t\t\tthrow new TransformationException( \"Error transforming one-to-many : \" + hbmCollection.getName(), e, origin() );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( hbmCollection.getManyToMany() != null ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif ( hbmCollection.getManyToMany().isUnique() ) {\n\t\t\t\t\t\t\tattributes.getOneToManyAttributes().add( transformManyToManyToOneToMany( hbmCollection, propertyInfo ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tattributes.getManyToManyAttributes().add( transformManyToMany( hbmCollection, propertyInfo ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Exception e) {\n\t\t\t\t\t\tthrow new TransformationException( \"Error transforming many-to-many : \" + hbmCollection.getName(), e, origin() );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( hbmCollection.getManyToAny() != null ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tattributes.getPluralAnyMappingAttributes().add( transformPluralAny( hbmCollection ) );\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Exception e) {\n\t\t\t\t\t\tthrow new TransformationException( \"Error transforming many-to-any : \" + hbmCollection.getName(), e, origin() );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new UnsupportedOperationException( \"Unexpected node type - \" + hbmCollection );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate JaxbBasicImpl transformBasicAttribute(final JaxbHbmBasicAttributeType hbmProp, PropertyInfo propertyInfo) {","sourceCodeStart":2213,"sourceCodeEnd":2249,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java#L2213-L2249","documentation":"Thrown by HbmXmlTransformer when transforming a <many-to-many/> collection fails. Note the two code paths in the source: many-to-many with unique=\"true\" is routed through transformManyToManyToOneToMany and still lands in this catch. The wrapped cause and the Origin identify the real failure.","triggerScenarios":"Transforming a plural attribute with a <many-to-many> child where the target class cannot be resolved, the join table/column configuration is invalid, or (unique=\"true\") the one-to-many reinterpretation fails because no usable inverse mapping can be derived.","commonSituations":"Migrating association-heavy legacy schemas; unique=\"true\" many-to-many mappings that the transformer tries to reinterpret as one-to-many; target entity of the association not included in the transformation set.","solutions":["Check exception.getCause() for the concrete failure","Verify the many-to-many 'class' attribute resolves to a mapped entity in the same run","If unique=\"true\" is set, consider whether the mapping is really a one-to-many and rewrite it as such before transforming","Validate join table, key and order-by/foreign-key declarations on both sides of the association","Fall back to binding the original hbm.xml natively when the transformer cannot express the mapping"],"exampleFix":"<!-- before: unique m2m that the transformer reinterprets -->\n<set name=\"perms\" table=\"user_perm\" unique=\"true\">\n    <key column=\"user_id\"/>\n    <many-to-many class=\"com.acme.Perm\" column=\"perm_id\"/>\n</set>\n\n<!-- after: express it as the one-to-many it really is -->\n<set name=\"perms\" inverse=\"true\">\n    <key column=\"user_id\"/>\n    <one-to-many class=\"com.acme.Perm\"/>\n</set>","handlingStrategy":"try-catch","validationCode":"// flag unique=\"true\" many-to-many ahead of time - the transformer reinterprets them\nvar m2m = doc.getElementsByTagName(\"many-to-many\");\nfor (int i = 0; i < m2m.getLength(); i++) {\n    var parent = (org.w3c.dom.Element) m2m.item(i).getParentNode();\n    if (\"true\".equals(((org.w3c.dom.Element) m2m.item(i)).getAttribute(\"unique\"))) {\n        warn(\"many-to-many with unique=true on '\" + parent.getAttribute(\"name\") + \"' - rewrite as one-to-many before transform\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    transformer.transform(hbmSource);\n} catch (TransformationException e) {\n    log.error(\"many-to-many transform failed: {}\", e.getMessage(), e.getCause());\n    throw e;\n}","preventionTips":["Rewrite unique many-to-many mappings as one-to-many before migration","Ensure both sides of the association are in the transformation set","Validate join table/column attributes on both ends of the association"],"tags":["hibernate","hbm-xml","many-to-many","mapping-transformation","orm"],"backgroundTag":"orm-mapping-transformation-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}