apache/seatunnel · error · org.apache.seatunnel.common.exception.SeaTunnelRuntimeException

COMMON-17

COMMON-17

Error message

'<identifier>' unsupported convert type '<dataType>' of '<field>' to SeaTunnel data type.

What it means

IcebergTypeMapper.mapping converts an Iceberg Type to a SeaTunnel type. If the Iceberg type is not one of the handled kinds (primitives, STRUCT, LIST, MAP — e.g. certain nested or logical types), the default branch throws COMMON-17 convertToSeaTunnelTypeError with 'Iceberg', the type's toString, and the field name.

Solutions

  1. Identify the unsupported Iceberg type from the error message (dataType field)
  2. Change the column type in the Iceberg table (e.g. cast fixed/uuid to binary/string where supported)
  3. Upgrade SeaTunnel to a version whose IcebergTypeMapper supports the type
  4. Add a mapping case for the type in a custom build of IcebergTypeMapper

Example fix

// before
Types.UUIDType.get()
// after
Types.StringType.get()
Defensive patterns

Strategy: validation

Validate before calling

// Validate Iceberg types before mapping
org.apache.iceberg.types.TypeUtil.visit(icebergSchema.asStruct(),
    new org.apache.iceberg.types.TypeUtil.CustomOrderTypeVisitor<Object>(null) {
        @Override public Object primitive(org.apache.iceberg.types.Types.PrimitiveType p) {
            if (p.typeId() == org.apache.iceberg.types.Type.TypeID.UUID
                || p.typeId() == org.apache.iceberg.types.Type.TypeID.FIXED) {
                throw new IllegalArgumentException("Unsupported Iceberg type: " + p);
            }
            return null;
        }
    });

Type guard

boolean isSupportedIcebergType(org.apache.iceberg.types.Type t) {
    switch (t.typeId()) {
        case BOOLEAN: case INTEGER: case LONG: case FLOAT:
        case DOUBLE: case STRING: case DATE: case TIMESTAMP:
        case DECIMAL: case BINARY: case STRUCT: case LIST: case MAP:
            return true;
        default:
            return false; // e.g. UUID, FIXED
    }
}

Prevention

When it happens

Trigger: mapping() is called with an Iceberg Types.Type whose TypeID falls into the switch default — e.g. nested types not covered by the handled cases or unusual logical types reached recursively from struct/map/list fields.

Common situations: Iceberg tables with UUID, fixed(n), or time-type columns reached in nested positions; tables written by newer Iceberg writers with types added after this mapper was written; deep nested structs containing exotic leaf types.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/f4e8e4b052117372. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-iceberg/src/main/java/org/apache/seatunnel/connectors/seatunnel/iceberg/data/IcebergTypeMapper.java:80

                }
                // withoutZone() → NTZ → TIMESTAMP
                return LocalTimeType.LOCAL_DATE_TIME_TYPE;
            case STRING:
                return BasicType.STRING_TYPE;
            case FIXED:
            case BINARY:
                return PrimitiveByteArrayType.INSTANCE;
            case DECIMAL:
                Types.DecimalType decimalType = (Types.DecimalType) icebergType;
                return new DecimalType(decimalType.precision(), decimalType.scale());
            case STRUCT:
                return mappingStructType((Types.StructType) icebergType);
            case LIST:
                return mappingListType(field, (Types.ListType) icebergType);
            case MAP:
                return mappingMapType(field, (Types.MapType) icebergType);
            default:
                throw CommonError.convertToSeaTunnelTypeError(
                        "Iceberg", icebergType.toString(), field);
        }
    }

    private static SeaTunnelRowType mappingStructType(Types.StructType structType) {
        List<Types.NestedField> fields = structType.fields();
        List<String> fieldNames = new ArrayList<>(fields.size());
        List<SeaTunnelDataType<?>> fieldTypes = new ArrayList<>(fields.size());
        for (Types.NestedField field : fields) {
            fieldNames.add(field.name());
            fieldTypes.add(mapping(field.name(), field.type()));
        }
        return new SeaTunnelRowType(
                fieldNames.toArray(new String[0]), fieldTypes.toArray(new SeaTunnelDataType[0]));
    }

    private static ArrayType mappingListType(String field, Types.ListType listType) {
        switch (listType.elementType().typeId()) {

View on GitHub (pinned to cf67b549a7)