{"record":{"id":"8e95c5fff09bdb41","repo":"hibernate/hibernate-orm","slug":"dialect-does-not-support-structured-array-types","errorCode":null,"errorMessage":"Dialect does not support structured array types: ${dialectClassName}","messagePattern":"Dialect does not support structured array types: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java","lineNumber":108,"sourceCode":"\t\t\t\t\t\t\tcomponentClassDetails,\n\t\t\t\t\t\t\tinferredData.getPropertyName(),\n\t\t\t\t\t\t\tcontext\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate static <T> void registerDescriptor(Class<T> componentClass, TypeConfiguration typeConfiguration, String structName) {\n\t\ttypeConfiguration.getJavaTypeRegistry()\n\t\t\t\t.resolveDescriptor( componentClass,\n\t\t\t\t\t\t() -> new EmbeddableAggregateJavaType<>( componentClass, structName ) );\n\t}\n\n\tprivate static int getStructPluralSqlTypeCode(MetadataBuildingContext context) {\n\t\treturn switch ( context.getPreferredSqlTypeCodeForArray() ) {\n\t\t\tcase SqlTypes.ARRAY -> SqlTypes.STRUCT_ARRAY;\n\t\t\tcase SqlTypes.TABLE -> SqlTypes.STRUCT_TABLE;\n\t\t\tdefault -> throw new UnsupportedOperationException(\n\t\t\t\t\t\"Dialect does not support structured array types: \"\n\t\t\t\t\t+ context.getMetadataCollector().getDatabase()\n\t\t\t\t\t\t\t.getDialect().getClass().getName()\n\t\t\t);\n\t\t};\n\t}\n\n\tprivate static QualifiedName determineStructName(\n\t\t\tPropertyData inferredData,\n\t\t\tClassDetails returnedClassOrElement,\n\t\t\tMetadataBuildingContext context) {\n\t\tfinal var memberDetails = inferredData.getAttributeMember();\n\t\tif ( memberDetails != null ) {\n\t\t\tfinal var struct = memberDetails.getDirectAnnotationUsage( Struct.class );\n\t\t\tif ( struct != null ) {\n\t\t\t\treturn toQualifiedName( struct, context );\n\t\t\t}\n\t\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java#L90-L126","documentation":"AggregateComponentBinder assigns a SQL type code when a struct aggregate (an @Struct embeddable) is mapped as a plural attribute (array or collection). It maps a preferred array code of SqlTypes.ARRAY to STRUCT_ARRAY and SqlTypes.TABLE to STRUCT_TABLE; any other preferred code - most commonly SqlTypes.JSON, which dialects without native arrays (MySQL/MariaDB family) prefer - has no structured equivalent, so an UnsupportedOperationException naming the dialect class is thrown.","triggerScenarios":"Mapping List<StructEmbeddable> or @Array on a @Struct-annotated embeddable while the effective preferred array type code (dialect default, or hibernate.type.preferred_array_jdbc_type / MetadataBuilder.applyPreferredSqlTypeCodeForArray) is JSON or another non-ARRAY/TABLE code.","commonSituations":"Running the same mapping on PostgreSQL in production but MySQL/H2 in tests; setting a global preferred-array JSON setting for basic arrays and forgetting it also affects struct arrays; migrating from Hibernate 6 to 7 where structured array handling was tightened.","solutions":["Remove @Struct from the embeddable so elements are no longer bound to a structured SQL type","Run against a database/dialect whose preferred array code is ARRAY (e.g. PostgreSQL, Oracle, DB2)","Undo the JSON preference: remove the hibernate.type.preferred_array_jdbc_type setting or set it to ARRAY (SqlTypes.ARRAY) where struct arrays must work","Remap the plural attribute as a plain basic array (e.g. List<String> or a JSON-mapped type) instead of an aggregate struct"],"exampleFix":"// before: struct aggregate inside a plural attribute on a JSON-array dialect\n@Embeddable\n@Struct(name = \"address\")\npublic class Address { ... }\n\n@Entity\npublic class Customer {\n    @Array                       // needs STRUCT_ARRAY/STRUCT_TABLE\n    private List<Address> addresses;\n}\n// with hibernate.type.preferred_array_jdbc_type = JSON (or MySQL dialect) -> UnsupportedOperationException\n\n// after: drop the struct binding, or target an ARRAY dialect\n@Embeddable                     // no @Struct: stored as plain aggregate/JSON\npublic class Address { ... }\n\n// or keep @Struct only when the dialect prefers SqlTypes.ARRAY (PostgreSQL etc.)","handlingStrategy":"validation","validationCode":"// Before defining struct arrays: assert the effective array code supports structures\nstatic boolean dialectSupportsStructArrays(Dialect dialect) {\n    int code = dialect.getPreferredSqlTypeCodeForArray();\n    return code == SqlTypes.ARRAY || code == SqlTypes.TABLE;\n}\n\n// In a test: fail fast with a clear message instead of a boot crash\nAssume.assumeTrue(\"Dialect cannot store struct arrays\",\n        dialectSupportsStructArrays(actualDialect()));","typeGuard":null,"tryCatchPattern":"try {\n    sessionFactory = metadata.buildSessionFactory();\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage().startsWith(\"Dialect does not support structured array types\")) {\n        throw new IllegalStateException(\"Struct aggregates in arrays are not usable with this database - \"\n                + \"remove @Struct or switch the dialect\", e);\n    }\n    throw e;\n}","preventionTips":["Keep struct-array mappings behind a database profile; guard tests with a capability assumption","Do not set a global preferred array JDBC type without checking it also fits aggregate mappings","Document which databases each entity model supports when using @Struct"],"tags":["hibernate","struct","array","aggregate","dialect","unsupported-operation","mapping"],"backgroundTag":"dialect-capability-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}