hibernate/hibernate-orm · error · UnsupportedOperationException
Unsupported JdbcType nested in struct: {}
Error message
Unsupported JdbcType nested in struct: {} What it means
When Hibernate serializes the attributes of a PostgreSQL composite/struct into the ROW(...) literal used for binding (AbstractPostgreSQLStructJdbcType.serializeJdbcValuesTo), it switches on each attribute's SQL type class. Only types handled by explicit cases (strings, numerics, booleans, nested STRUCTs, arrays, etc.) can be written; anything else falls through to the default branch and throws UnsupportedOperationException naming the unsupported JdbcType. The error means: one attribute of your @Struct mapping uses a JDBC type Hibernate cannot render inside a PostgreSQL struct literal.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/type/AbstractPostgreSQLStructJdbcType.java:1286
}
}
appender.append( '}' );
appender.quoteEnd();
}
}
break;
case SqlTypes.STRUCT:
if ( subValue != null ) {
final var structJdbcType = (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType();
appender.quoteStart();
structJdbcType.serializeJdbcValuesTo( appender, options, (Object[]) subValue, '(' );
appender.append( ')' );
appender.quoteEnd();
}
break;
default:
throw new UnsupportedOperationException( "Unsupported JdbcType nested in struct: " + jdbcMapping.getJdbcType() );
}
}
private StructAttributeValues getAttributeValues(
EmbeddableMappingType embeddableMappingType,
int[] orderMapping,
Object[] rawJdbcValues,
WrapperOptions options) throws SQLException {
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
final int size = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
final StructAttributeValues attributeValues = new StructAttributeValues(
numberOfAttributeMappings,
orderMapping != null ?
null :
rawJdbcValues
);
int jdbcIndex = 0;
for ( int i = 0; i < size; i++ ) {View on GitHub (pinned to fad1729dce)
Solutions
- Change the offending attribute to a type the serializer supports (String, Integer, Long, BigDecimal, Boolean, another @Struct embeddable, or an array of those).
- Convert the attribute to String via @Converter / @JdbcTypeCode(SqlTypes.VARCHAR) so the struct stores its text representation.
- Implement a custom JdbcType extending AbstractPostgreSQLStructJdbcType that overrides the serialization switch to handle your nested type.
- Move the exotic value out of the struct into its own column or side table.
- Check the Hibernate release notes - the set of nested types supported in struct literals grows across versions, so upgrade may alone fix it.
Example fix
// before
@Embeddable
@Struct(name = "address_type")
public class Address {
private String city; // OK
private UUID tenantId; // throws: Unsupported JdbcType nested in struct
}
// after
@Embeddable
@Struct(name = "address_type")
public class Address {
private String city;
@JdbcTypeCode(SqlTypes.VARCHAR)
private String tenantId; // store UUID as text inside the struct
} Defensive patterns
Strategy: validation
Validate before calling
// At startup, verify every @Struct embeddable attribute maps to a serializer-supported Java type
static void checkStructAttributes(Class<?> embeddable) {
Set<Class<?>> ok = Set.of(String.class, Integer.class, Long.class, BigDecimal.class, Boolean.class);
for (Field f : embeddable.getDeclaredFields()) {
Class<?> t = f.getType();
boolean supported = ok.contains(t) || t.isAnnotationPresent(Struct.class) || t.isArray();
if (!supported) throw new IllegalStateException(
"@Struct " + embeddable.getSimpleName() + "." + f.getName()
+ " of type " + t + " is not serializable inside a PostgreSQL struct");
}
} Try / catch
catch (UnsupportedOperationException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Unsupported JdbcType nested in struct")) {
// message names the JdbcType; map that attribute as String or implement a custom JdbcType
throw new MappingConfigurationException(e.getMessage(), e);
}
throw e;
} Prevention
- Keep @Struct embeddables to primitives, String, BigDecimal, Boolean, nested structs, and arrays; keep UUID/JSON/temporal values out of them.
- Cover struct mappings with a smoke test that inserts and reads one row per embeddable, so unsupported attributes fail in CI, not production.
- Review Hibernate release notes when adding new attribute types to existing structs.
When it happens
Trigger: An embeddable mapped with @Struct / SqlTypes.STRUCT on PostgreSQL containing an attribute whose JdbcType is outside the serializer's switch - typical culprits: UUID, JSON/JSONB, java.time types with bespoke JdbcTypes, custom enum JdbcTypes, BINARY/VARBINARY, INTERVAL. The exception fires on INSERT/UPDATE/flush, i.e. whenever the struct literal must be built and sent.
Common situations: Adopting PostgreSQL composite types (@Struct) and reusing an existing embeddable that contains a UUID or JSON attribute; mapping a domain object designed for embedded columns directly as a DB composite; upgrading Hibernate and having previously-tolerated attribute types now hit the default branch.
Related errors
- Array not properly formed: {}
- Struct not properly formed: {}
- Unsupported JdbcType nested in struct:
- Unsupported JdbcType nested in JSON: {}
- Unsupported JdbcType nested in JSON: {}
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/0104c6f956d9d4d0.
Report an issue: GitHub.