{"record":{"id":"672a918868ec783c","repo":"hibernate/hibernate-orm","slug":"struct-s-of-class-s-is-defined-by-multiple-c","errorCode":null,"errorMessage":"Struct [%s] of class [%s] is defined by multiple components with different mappings [%s] and [%s] for column [%s]","messagePattern":"Struct \\[(.+?)\\] of class \\[(.+?)\\] is defined by multiple components with different mappings \\[(.+?)\\] and \\[(.+?)\\] for column \\[(.+?)\\]","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java","lineNumber":412,"sourceCode":"\t\t\tthrow new MappingException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"Struct [%s] is defined by multiple components %s with different number of mappings %d and %d\",\n\t\t\t\t\t\t\tudt1.getName(),\n\t\t\t\t\t\t\tfindComponentClasses(),\n\t\t\t\t\t\t\tudt1.getColumnSpan(),\n\t\t\t\t\t\t\tudt2.getColumnSpan()\n\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\tfinal List<Column> missingColumns = new ArrayList<>();\n\t\tfor ( Column column1 : udt1.getColumns() ) {\n\t\t\tfinal Column column2 = udt2.getColumn( column1 );\n\t\t\tif ( column2 == null ) {\n\t\t\t\tmissingColumns.add( column1 );\n\t\t\t}\n\t\t\telse if ( !column1.getSqlType().equals( column2.getSqlType() ) ) {\n\t\t\t\tthrow new MappingException(\n\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\"Struct [%s] of class [%s] is defined by multiple components with different mappings [%s] and [%s] for column [%s]\",\n\t\t\t\t\t\t\t\tudt1.getName(),\n\t\t\t\t\t\t\t\tcomponentClassDetails.getName(),\n\t\t\t\t\t\t\t\tcolumn1.getSqlType(),\n\t\t\t\t\t\t\t\tcolumn2.getSqlType(),\n\t\t\t\t\t\t\t\tcolumn1.getCanonicalName()\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif ( !missingColumns.isEmpty() ) {\n\t\t\tthrow new MappingException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"Struct [%s] is defined by multiple components %s but some columns are missing in [%s]: %s\",\n\t\t\t\t\t\t\tudt1.getName(),\n\t\t\t\t\t\t\tfindComponentClasses(),","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java#L394-L430","documentation":"The second stage of validateEqual for struct definitions sharing one name: matching columns must also agree on SQL type. If column X maps to varchar(255) in one component and to a Clob/varchar(10)/different type in the other, Hibernate throws this MappingException showing the struct name, component class, both SQL types, and the column.","triggerScenarios":"Two embeddables with the same @Struct(name=...) declare the same field names but with different mapped types or column definitions - e.g. String vs @Lob String, different lengths, an enum mapped STRING vs ORDINAL, or different @JdbcTypeCode.","commonSituations":"Two teams mapping the same UDT independently; refactoring one embeddable's types without updating its twin; copy-paste divergence where a length or Lob annotation was added on one side only.","solutions":["Align the type mapping of the differing column in both components (same JDBC type, length, Lob usage)","Preferably collapse both components into one canonical embeddable class","If the databases/UDTs truly differ, rename one struct so the definitions stop colliding"],"exampleFix":"// before: same struct, same field, different SQL type\n@Embeddable @Struct(name = \"note\")\npublic class NoteA { @Column(length = 100) String text; }\n\n@Embeddable @Struct(name = \"note\")\npublic class NoteB { @Lob String text; }        // CLOB vs varchar -> error\n\n// after: identical mapping\n@Embeddable @Struct(name = \"note\")\npublic class NoteA { @Column(length = 100) String text; }\n\n@Embeddable @Struct(name = \"note\")\npublic class NoteB { @Column(length = 100) String text; }","handlingStrategy":"validation","validationCode":"// Before boot: embeddables sharing a struct name must agree on every column's SQL shape\nstatic boolean structColumnTypesAgree(Class<?> a, Class<?> b) {\n    Map<String, Column> colsB = columnMap(b);\n    for (Map.Entry<String, Column> e : columnMap(a).entrySet()) {\n        Column other = colsB.get(e.getKey());\n        if (other == null) return false;\n        if (e.getValue().length() != other.length()\n                || e.getValue().lob() != other.lob()) return false;\n    }\n    return colsB.keySet().equals(columnMap(a).keySet());\n}","typeGuard":null,"tryCatchPattern":"try {\n    sessionFactory = metadata.buildSessionFactory();\n} catch (MappingException e) {\n    if (e.getMessage().contains(\"different mappings\")) {\n        throw new IllegalStateException(\"Diverging column types between components of one struct\", e);\n    }\n    throw e;\n}","preventionTips":["Maintain exactly one embeddable per database struct","When a struct's column type changes, grep for every @Struct with that name","Include column length/@Lob/enum mapping in code review for struct embeddables"],"tags":["hibernate","struct","column-type-mismatch","mapping","udt"],"backgroundTag":"struct-definition-conflict","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}