apache/iceberg · error · IllegalStateException
Invalid Timestamp type unit
Error message
Invalid Timestamp type unit: %s
What it means
When converting an ORC TIMESTAMP primitive (timestamp without zone) to an Iceberg type, OrcToIcebergVisitor reads the ORC-ICEBERG type attribute TIMESTAMP_UNIT. Only 'M'/'MICROS' (default when null) and 'N'/'NANOS' are valid; any other attribute value throws IllegalStateException. The attribute is set when Iceberg writes ORC files, so a bad value indicates corrupted or hand-edited metadata.
Solutions
- Rewrite the ORC file with a supported unit attribute (MICROS or NANOS) — e.g. write through Iceberg so the attribute is set correctly.
- Inspect the attribute with the ORC tooling and correct TIMESTAMP_UNIT to 'M' or 'N'.
- Remove the bogus attribute entirely: a null unit defaults to MICROS and will convert cleanly.
- Upgrade Iceberg if a version wrote a unit token that your reader version does not recognize.
Example fix
// before (bad attribute) TIMESTAMP_UNIT = "milliseconds" // after TIMESTAMP_UNIT = "N" // NANOS, or remove attribute to default to MICROS
Defensive patterns
Strategy: validation
Validate before calling
String unit = primitive.getAttributeValue(ORCSchemaUtil.TIMESTAMP_UNIT);
if (unit != null && !ORCSchemaUtil.MICROS.equalsIgnoreCase(unit) && !ORCSchemaUtil.NANOS.equalsIgnoreCase(unit)) {
throw new IllegalArgumentException("Bad TIMESTAMP_UNIT: " + unit);
} Try / catch
try { schema = ORCSchemaUtil.convert(orcSchema); } catch (IllegalStateException e) { if (e.getMessage().startsWith("Invalid Timestamp type unit")) { repairAttributeOrRewrite(file); } else throw e; } Prevention
- Never hand-edit ORC type attributes
- Write ORC files through Iceberg so TIMESTAMP_UNIT is set canonically
- Verify attributes of externally produced ORC files before registration
- Keep writer and reader Iceberg versions aligned
When it happens
Trigger: Reading an ORC file whose TIMESTAMP column carries ORCSchemaUtil.TIMESTAMP_UNIT attribute value other than MICROS/NANOS (case-insensitive), during ORC→Iceberg schema conversion.
Common situations: Files written by other engines or older/custom Iceberg forks that wrote a different unit token; manually patched ORC metadata; corrupted custom attributes.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid Long type found in ORC type attribute
- Can't handle
- Invalid Binary type found in ORC type attribute
- Avro does not support LOCAL TIMESTAMP type with precision
- Avro does not support LOCAL TIMESTAMP type with precision…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8b6c81386b7b22ea.
Report an issue: GitHub.
Appendix: source
Thrown at orc/src/main/java/org/apache/iceberg/orc/OrcToIcebergVisitor.java:175
case STRING:
case CHAR:
case VARCHAR:
builder.ofType(Types.StringType.get());
break;
case BINARY:
convertBinary(primitive, builder);
break;
case DATE:
builder.ofType(Types.DateType.get());
break;
case TIMESTAMP:
String unit = primitive.getAttributeValue(ORCSchemaUtil.TIMESTAMP_UNIT);
if (unit == null || ORCSchemaUtil.MICROS.equalsIgnoreCase(unit)) {
builder.ofType(Types.TimestampType.withoutZone());
} else if (unit.equalsIgnoreCase(ORCSchemaUtil.NANOS)) {
builder.ofType(Types.TimestampNanoType.withoutZone());
} else {
throw new IllegalStateException(String.format("Invalid Timestamp type unit: %s", unit));
}
break;
case TIMESTAMP_INSTANT:
String tsUnit = primitive.getAttributeValue(ORCSchemaUtil.TIMESTAMP_UNIT);
if (tsUnit == null || ORCSchemaUtil.MICROS.equalsIgnoreCase(tsUnit)) {
builder.ofType(Types.TimestampType.withZone());
} else if (tsUnit.equalsIgnoreCase(ORCSchemaUtil.NANOS)) {
builder.ofType(Types.TimestampNanoType.withZone());
} else {
throw new IllegalStateException(String.format("Invalid Timestamp type unit: %s", tsUnit));
}
break;
case DECIMAL:
builder.ofType(Types.DecimalType.of(primitive.getPrecision(), primitive.getScale()));
break;
default:View on GitHub (pinned to 86d9c8fc54)