apache/iceberg · error · java.lang.UnsupportedOperationException
Unsupported StructuredType.
Error message
Unsupported StructuredType.
What it means
Flink StructuredType is an anonymous structured/record logical type (e.g. from class-based UDTs) with no direct Iceberg mapping, so FlinkTypeVisitor throws UnsupportedOperationException when it is visited. Iceberg conversion expects concrete row types it can map to Iceberg StructType.
Source
Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/FlinkTypeVisitor.java:58
@Override
public T visit(YearMonthIntervalType yearMonthIntervalType) {
throw new UnsupportedOperationException("Unsupported YearMonthIntervalType.");
}
@Override
public T visit(DayTimeIntervalType dayTimeIntervalType) {
throw new UnsupportedOperationException("Unsupported DayTimeIntervalType.");
}
@Override
public T visit(DistinctType distinctType) {
throw new UnsupportedOperationException("Unsupported DistinctType.");
}
@Override
public T visit(StructuredType structuredType) {
throw new UnsupportedOperationException("Unsupported StructuredType.");
}
@Override
public T visit(NullType nullType) {
throw new UnsupportedOperationException("Unsupported NullType.");
}
@Override
public T visit(RawType<?> rawType) {
throw new UnsupportedOperationException("Unsupported RawType.");
}
@Override
public T visit(SymbolType<?> symbolType) {
throw new UnsupportedOperationException("Unsupported SymbolType.");
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Convert the UDT column to an explicit ROW(...) type, e.g. CAST(obj AS ROW<a INT, b STRING>), so Iceberg maps it to StructType.
- Flatten the structured column into individual scalar columns before the Iceberg sink.
- Remove the structured column from the Iceberg table schema if it is not needed.
- Override visit(StructuredType) in a custom FlinkTypeVisitor subclass to map fields to an Iceberg StructType.
Example fix
// before INSERT INTO iceberg_t SELECT my_udt_col FROM src; // StructuredType // after INSERT INTO iceberg_t SELECT CAST(my_udt_col AS ROW<x INT, y STRING>) AS r FROM src;
Defensive patterns
Strategy: validation
Validate before calling
import org.apache.flink.table.types.logical.LogicalType;
import org.apache.flink.table.types.logical.StructuredType;
static boolean containsStructuredType(org.apache.flink.table.api.Schema schema) {
return schema.getColumns().stream()
.anyMatch(c -> c.getType().getLogicalType() instanceof StructuredType);
} Type guard
static boolean isStructuredType(LogicalType t) {
return t instanceof StructuredType;
} Prevention
- Prefer explicit ROW(...) types over class-based UDTs in Iceberg sink pipelines.
- Cast UDT columns to ROW types with explicit fields before the sink.
- Flatten structured columns into scalar columns where possible.
- Pin consistent Flink versions so type inference is stable across upgrades.
When it happens
Trigger: Converting a row type containing a StructuredType column, typically produced by Java/Scala class UDTs or connectors emitting structured logical types, when running FlinkTypeVisitor-based schema conversion.
Common situations: Sink queries that include UDT columns feeding Iceberg; Flink version differences where inference yields StructuredType where an older version inferred RowType; object constructors in SELECT lists producing structured types.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Unsupported YearMonthIntervalType.
- Unsupported DayTimeIntervalType.
- Unsupported DistinctType.
- Unsupported type: %s
- Unsupported NullType.
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/22aff1fbd2b9e45d.
Report an issue: GitHub.