apache/iceberg · error · UnsupportedOperationException

UnsupportedOperationException with no message (TimestampInt9

Error message

UnsupportedOperationException with no message (TimestampInt96Reader.nextDictEncodedVal)

What it means

TimestampInt96Reader.nextDictEncodedVal is implemented to always throw an UnsupportedOperationException with no message — INT96 timestamps are simply not supported in dictionary-encoded vectorized decoding. Unlike error 292 (which has a message for unknown modes), this is an unconditional refusal.

Source

Thrown at arrow/src/main/java/org/apache/iceberg/arrow/vectorized/parquet/VectorizedParquetDefinitionLevelReader.java:652

        FieldVector vector,
        int idx,
        VectorizedValuesReader valuesReader,
        int typeWidth,
        byte[] byteArray) {
      ((BitVector) vector).setSafe(idx, valuesReader.readBoolean() ? 1 : 0);
    }

    @Override
    protected void nextDictEncodedVal(
        FieldVector vector,
        int idx,
        VectorizedDictionaryEncodedParquetValuesReader reader,
        Dictionary dict,
        Mode mode,
        int numValues,
        NullabilityHolder holder,
        int typeWidth) {
      throw new UnsupportedOperationException();
    }
  }

  class DictionaryIdReader extends BaseReader {

    @Override
    protected void nextVal(
        FieldVector vector,
        int idx,
        VectorizedValuesReader valuesReader,
        int typeWidth,
        byte[] byteArray) {
      throw new UnsupportedOperationException();
    }

    @Override
    protected void nextDictEncodedVal(
        FieldVector vector,

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Disable vectorized reads (read.parquet.vectorization.enabled=false) to fall back to the generic reader.
  2. Rewrite/compact the table converting INT96 timestamps to INT64 with a timestamp logical type.
  3. Implement nextDictEncodedVal for INT96 if dictionary-encoded INT96 support is needed.

Example fix

// before
spark.read.format("iceberg").load("db.table") // fails on dict-encoded INT96
// after
table.newScan().option("read.parquet.vectorization.enabled", "false");
Defensive patterns

Strategy: fallback

Validate before calling

boolean isInt96 = desc.getPrimitiveType().getPrimitiveTypeName() == PrimitiveTypeName.INT96;
boolean dictEncoded = pageEncoding != null && pageEncoding.isDictionaryEncoded();
if (isInt96 && dictEncoded) { vectorizationSupported = false; }

Try / catch

try {
  return readVectorizedBatch();
} catch (UnsupportedOperationException e) {
  return readRowOrientedBatch(); // non-vectorized path supports INT96
}

Prevention

When it happens

Trigger: Any call to nextDictEncodedVal on a TimestampInt96Reader, i.e. vectorized reading of a dictionary-encoded INT96 timestamp column that takes the dictionary decode path (e.g. packed dictionary decoding).

Common situations: Legacy Parquet files (Hive/Impala/old Spark) storing timestamps as INT96 with dictionary-encoded pages read through the Iceberg vectorized Arrow reader; the vectorized INT96 reader only supports plain (non-dictionary) reads.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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