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

  1. Rewrite the ORC file with a supported unit attribute (MICROS or NANOS) — e.g. write through Iceberg so the attribute is set correctly.
  2. Inspect the attribute with the ORC tooling and correct TIMESTAMP_UNIT to 'M' or 'N'.
  3. Remove the bogus attribute entirely: a null unit defaults to MICROS and will convert cleanly.
  4. 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

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


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)