apache/iceberg · error · IllegalArgumentException
Unhandled type
Error message
Unhandled type
What it means
SparkOrcWriter.primitive() maps Iceberg primitive types to ORC value writers. If it encounters an Iceberg primitive type with no ORC writer mapping (anything not covered by the switch cases, e.g. types invalid for ORC storage), it throws IllegalArgumentException("Unhandled type ..."). This fails writer creation for the whole file, before any rows are written.
Solutions
- Check the offending Iceberg type in the table schema (spark printSchema / metadata) and convert it to an ORC-supported type
- Recreate or alter the table with an ORC-compatible column type (e.g. use string/long instead of the unsupported type)
- If the type is a newly added Iceberg spec type, upgrade Iceberg to a version whose Spark writer supports it
- Cast unsupported columns before writing (e.g. df.withColumn("c", col("c").cast("string")))
Example fix
// before
df.writeTo("db.table_unsupported_type").append();
// after
Dataset<Row> fixed = df.withColumn("weird", functions.col("weird").cast("string"));
fixed.writeTo("db.table").append(); Defensive patterns
Strategy: validation
Validate before calling
for (Types.NestedField f : table.schema().columns()) {
if (f.type().isPrimitiveType() && !ORC_SUPPORTED_TYPES.contains(f.type().asPrimitiveType().typeId())) {
throw new IllegalStateException("Column " + f.name() + " has ORC-unsupported type " + f.type());
}
} Type guard
boolean isOrcWritable(Type type) {
switch (type.typeId()) {
case BOOLEAN: case INT: case LONG: case FLOAT: case DOUBLE: case DATE:
case TIME: case TIMESTAMP: case STRING: case UUID: case FIXED:
case BINARY: case DECIMAL: return true;
default: return false;
}
} Try / catch
try {
df.writeTo("db.tbl").append();
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Unhandled type")) {
// recast offending columns to ORC-supported types and retry
} else {
throw e;
}
} Prevention
- Verify every table column type is ORC-representable before choosing write.format=orc
- Cast exotic columns (e.g. unknown/future spec types) to string or binary before writing
- Keep Iceberg versions aligned across producers and this Spark integration
When it happens
Trigger: Writing a Spark DataFrame via the Iceberg ORC writer when the table schema contains an Iceberg primitive type not handled by the switch (e.g. Iceberg types that ORC cannot represent or that newer spec versions added without writer support in this Spark 4.0 branch).
Common situations: Migrating tables between formats and landing a type ORC does not support (e.g. UUID or unknown future types in this branch); using a table whose schema was created with a newer Iceberg spec than this writer supports; accidental misuse of nested/binary types mapped incorrectly to ORC.
Related errors
- Encountered an unsupported ORC type during a write from…
- Encountered an unsupported ORC type during a write from…
- Encountered an unsupported ORC type during a write from…
- Encountered an unsupported ORC type during a write from…
- Unhandled type
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/e124daabe2ad06bd.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/data/SparkOrcWriter.java:130
return GenericOrcWriters.floats(ORCSchemaUtil.fieldId(primitive));
case DOUBLE:
return GenericOrcWriters.doubles(ORCSchemaUtil.fieldId(primitive));
case BINARY:
if (Type.TypeID.UUID == iPrimitive.typeId()) {
return SparkOrcValueWriters.uuids();
}
return GenericOrcWriters.byteArrays();
case STRING:
case CHAR:
case VARCHAR:
return SparkOrcValueWriters.strings();
case DECIMAL:
return SparkOrcValueWriters.decimal(primitive.getPrecision(), primitive.getScale());
case TIMESTAMP_INSTANT:
case TIMESTAMP:
return SparkOrcValueWriters.timestampTz();
default:
throw new IllegalArgumentException("Unhandled type " + primitive);
}
}
}
private static class InternalRowWriter extends GenericOrcWriters.StructWriter<InternalRow> {
private final List<FieldGetter<?>> fieldGetters;
InternalRowWriter(
List<OrcValueWriter<?>> writers, Types.StructType iStruct, List<TypeDescription> orcTypes) {
super(iStruct, writers);
this.fieldGetters = Lists.newArrayListWithExpectedSize(orcTypes.size());
Map<Integer, TypeDescription> idToType =
orcTypes.stream().collect(Collectors.toMap(ORCSchemaUtil::fieldId, s -> s));
for (Types.NestedField iField : iStruct.fields()) {
fieldGetters.add(createFieldGetter(idToType.get(iField.fieldId())));
}View on GitHub (pinned to 86d9c8fc54)