{"record":{"id":"0136c3b03c1c348c","repo":"hibernate/hibernate-orm","slug":"couldn-t-find-column-structcolumnname-that-wa","errorCode":null,"errorMessage":"Couldn't find column [${structColumnName}] that was defined in @Struct(attributes) in the component [${componentClassName}]","messagePattern":"Couldn't find column \\[(.+?)\\] that was defined in @Struct\\(attributes\\) in the component \\[(.+?)\\]","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java","lineNumber":290,"sourceCode":"\t\t\t\t\taddColumns( orderedColumns, component.getDiscriminator() );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfinal List<Property> properties = component.getProperties();\n\t\t\t\tfor ( final int propertyIndex : propertyMappingIndex ) {\n\t\t\t\t\taddColumns( orderedColumns, properties.get( propertyIndex ).getValue() );\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinal List<Column> reorderedColumn =\n\t\t\t\t\tcontext.getBuildingOptions().getColumnOrderingStrategy()\n\t\t\t\t\t\t\t.orderUserDefinedTypeColumns( userDefinedType, context.getMetadataCollector() );\n\t\t\tuserDefinedType.reorderColumns( reorderedColumn != null ? reorderedColumn : orderedColumns );\n\t\t}\n\t\telse {\n\t\t\tfinal ArrayList<Column> orderedColumns = new ArrayList<>( userDefinedType.getColumnSpan() );\n\t\t\tfor ( String structColumnName : structColumnNames ) {\n\t\t\t\tif ( !addColumns( orderedColumns, component, structColumnName ) ) {\n\t\t\t\t\tthrow new MappingException( \"Couldn't find column [\" + structColumnName + \"] that was defined in @Struct(attributes) in the component [\" + component.getComponentClassName() + \"]\" );\n\t\t\t\t}\n\t\t\t}\n\t\t\tuserDefinedType.reorderColumns( orderedColumns );\n\t\t}\n\t}\n\n\tprivate static void addColumns(ArrayList<Column> orderedColumns, Value value) {\n\t\tif ( value instanceof Component subComponent ) {\n\t\t\tif ( subComponent.getAggregateColumn() == null ) {\n\t\t\t\tfor ( Property property : subComponent.getProperties() ) {\n\t\t\t\t\taddColumns( orderedColumns, property.getValue() );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\torderedColumns.add( subComponent.getAggregateColumn() );\n\t\t\t}\n\t\t}\n\t\telse {","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java#L272-L308","documentation":"@Struct(attributes = {...}) lists the ordered attribute (column) names of the database struct type. AggregateComponentSecondPass reorders the mapped columns to match that list; when a listed name matches no column of the component mapping (addColumns returns false), Hibernate throws this MappingException naming the offending struct column and the component class.","triggerScenarios":"A @Struct annotation whose attributes array contains a name that does not correspond to any mapped column of the embeddable - a typo, a different casing convention, or a field renamed via @Column after the struct attributes were written.","commonSituations":"Renaming embeddable fields or their @Column names without updating @Struct(attributes); adapting the Java model to a pre-existing database struct whose attribute spellings differ; case-sensitivity mismatches (USR_NAME vs usr_name) on case-sensitive DBs.","solutions":["Compare each @Struct attributes entry against the effective column names of the embeddable fields (@Column name if present, else the naming-strategy-derived name)","Fix the typo or casing so names match exactly","If the database struct name must stay, add @Column(name = \"...\") to the field to align it with the struct attribute","Last resort: drop the attributes list and let ordering follow the default strategy"],"exampleFix":"// before: struct attribute name does not match any mapped column\n@Embeddable\n@Struct(name = \"address\", attributes = {\"street\", \"zip\"})   // 'zip' maps nothing\npublic class Address {\n    private String street;\n    @Column(name = \"post_code\")\n    private String postCode;\n}\n\n// after: names aligned\n@Struct(name = \"address\", attributes = {\"street\", \"post_code\"})","handlingStrategy":"validation","validationCode":"// Before boot: every @Struct attribute must match an effective column name\nstatic List<String> structMismatches(Class<?> embeddable, PhysicalNamingStrategy ns) {\n    Set<String> cols = new HashSet<>();\n    for (Field f : embeddable.getDeclaredFields()) {\n        Column c = f.getAnnotation(Column.class);\n        cols.add(c != null && !c.name().isEmpty() ? c.name() : ns.toPhysicalColumnName(f.getName()));\n    }\n    return Arrays.stream(embeddable.getAnnotation(Struct.class).attributes())\n            .filter(a -> !cols.contains(a)).toList();\n}","typeGuard":null,"tryCatchPattern":"try {\n    sessionFactory = metadata.buildSessionFactory();\n} catch (MappingException e) {\n    if (e.getMessage().contains(\"that was defined in @Struct(attributes)\")) {\n        throw new IllegalStateException(\"Struct attribute names out of sync with embeddable columns\", e);\n    }\n    throw e;\n}","preventionTips":["Keep @Struct(attributes) and @Column names in one place; update them together","Write a unit test that cross-checks struct attribute names against mapped column names","Avoid renaming struct fields casually - the database UDT definition must stay in sync too"],"tags":["hibernate","struct","attributes","column-name","naming","mapping"],"backgroundTag":"annotation-name-mismatch-mapping","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}