apache/iceberg · error · UnsupportedOperationException

Unsupported unit for time

Error message

Unsupported unit for time: %s

What it means

GenericParquetReaders.timeReader selects a reader for Parquet TIME logical types based on the time unit. Only MICROS and MILLIS are supported; other units (e.g. NANOS for time) throw UnsupportedOperationException because the generic readers have no corresponding conversion.

Solutions

  1. Rewrite the file with time stored in MICROS or MILLIS (or as the corresponding Iceberg time type).
  2. Read with a reader implementation that supports the unit, or convert the column manually (read as long and scale).
  3. If you control the writer, configure it to emit microsecond-precision time logical types.

Example fix

// before: file has TIME(NANOS), generic reader throws
// after: rewrite column to micros
// df.withColumn("t", col("t").cast("timestamp")).write.parquet(...) // or re-write as int64 micros
Defensive patterns

Strategy: validation

Validate before calling

// Inspect time logical-type unit before reading
TimeUnit unit = col.getTimeUnit();
if (unit != TimeUnit.MICROSECONDS && unit != TimeUnit.MILLISECONDS) {
  throw new IllegalStateException("Rewrite file: unsupported time unit " + unit);
}

Prevention

When it happens

Trigger: Reading a Parquet file with a TIME logical type annotated with an unsupported unit (NANOS) through the generic Parquet reader path.

Common situations: Files written by tools that emit nanosecond time logical types (e.g. some Spark/other writers with NANOS time); reading non-Iceberg parquet files with generic readers.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/dcf1519ce987b134. Report an issue: GitHub.

Appendix: source

Thrown at parquet/src/main/java/org/apache/iceberg/data/parquet/GenericParquetReaders.java:92

    return new GenericParquetReaders.DateReader(desc);
  }

  @Override
  protected ParquetValueReader<?> timeReader(ColumnDescriptor desc) {
    LogicalTypeAnnotation time = desc.getPrimitiveType().getLogicalTypeAnnotation();
    Preconditions.checkArgument(
        time instanceof LogicalTypeAnnotation.TimeLogicalTypeAnnotation,
        "Invalid time logical type: " + time);

    LogicalTypeAnnotation.TimeUnit unit =
        ((LogicalTypeAnnotation.TimeLogicalTypeAnnotation) time).getUnit();
    switch (unit) {
      case MICROS:
        return new GenericParquetReaders.TimeReader(desc);
      case MILLIS:
        return new GenericParquetReaders.TimeMillisReader(desc);
      default:
        throw new UnsupportedOperationException("Unsupported unit for time: " + unit);
    }
  }

  @Override
  protected ParquetValueReader<?> timestampReader(ColumnDescriptor desc, boolean isAdjustedToUTC) {
    if (desc.getPrimitiveType().getPrimitiveTypeName() == PrimitiveType.PrimitiveTypeName.INT96) {
      return new GenericParquetReaders.TimestampInt96Reader(desc);
    }

    LogicalTypeAnnotation timestamp = desc.getPrimitiveType().getLogicalTypeAnnotation();
    Preconditions.checkArgument(
        timestamp instanceof LogicalTypeAnnotation.TimestampLogicalTypeAnnotation,
        "Invalid timestamp logical type: " + timestamp);

    LogicalTypeAnnotation.TimeUnit unit =
        ((LogicalTypeAnnotation.TimestampLogicalTypeAnnotation) timestamp).getUnit();
    switch (unit) {
      case NANOS:

View on GitHub (pinned to 86d9c8fc54)