apache/iceberg · error · UnsupportedOperationException

Unsupported mode for timestamp int96 reader: " + mode

Error message

Unsupported mode for timestamp int96 reader: " + mode

What it means

TimestampInt96Reader.nextDictEncodedVal dispatches on the decode Mode (the dictionary decoding strategy) and throws UnsupportedOperationException for any Mode it does not explicitly implement. Only the modes handled in its switch produce values; others are treated as unsupported for INT96 timestamp dictionary reads.

Source

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

        int numValues,
        NullabilityHolder holder,
        int typeWidth) {
      switch (mode) {
        case RLE:
          reader
              .timestampInt96DictEncodedReader()
              .nextBatch(vector, idx, numValues, dict, holder, typeWidth);
          break;
        case PACKED:
          ByteBuffer buffer =
              dict.decodeToBinary(reader.readInteger())
                  .toByteBuffer()
                  .order(ByteOrder.LITTLE_ENDIAN);
          long timestampInt96 = ParquetUtil.extractTimestampInt96(buffer);
          vector.getDataBuffer().setLong((long) idx * typeWidth, timestampInt96);
          break;
        default:
          throw new UnsupportedOperationException(
              "Unsupported mode for timestamp int96 reader: " + mode);
      }
    }
  }

  class FixedSizeBinaryReader extends BaseReader {
    @Override
    protected void nextVal(
        FieldVector vector,
        int idx,
        VectorizedValuesReader valuesReader,
        int typeWidth,
        byte[] byteArray) {
      valuesReader.readBinary(typeWidth).toByteBuffer().get(byteArray, 0, typeWidth);
      ((FixedSizeBinaryVector) vector).set(idx, byteArray);
    }

    @Override

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Rewrite the data with INT64 (TIMESTAMP_MICROS/MILLIS) logical type instead of INT96.
  2. Disable vectorized reads for these files to use the non-vectorized path.
  3. Add the missing Mode case to TimestampInt96Reader.nextDictEncodedVal if it should be supported.

Example fix

// before
throw new UnsupportedOperationException("Unsupported mode for timestamp int96 reader: " + mode);
// after
case RLE_DICTIONARY: // add the missing mode
  decodeWithRleDictionary(vector, idx, reader, dict, numValues, holder, typeWidth);
  break;
default:
  throw new UnsupportedOperationException("Unsupported mode for timestamp int96 reader: " + mode);
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check encoding before vectorized INT96 dictionary decode
boolean isInt96 = desc.getPrimitiveType().getPrimitiveTypeName() == PrimitiveTypeName.INT96;
boolean dictEncoded = pageEncoding != null && pageEncoding.isDictionaryEncoded();
if (isInt96 && dictEncoded) { disableVectorization = true; }

Try / catch

try {
  reader.nextDictEncodedVal(vector, idx, dictReader, dict, mode, numValues, holder, typeWidth);
} catch (UnsupportedOperationException e) {
  throw new IllegalArgumentException("INT96 dict decode mode unsupported: " + mode, e);
}

Prevention

When it happens

Trigger: Reading dictionary-encoded INT96 (legacy timestamp) Parquet pages where the dictionary decode Mode passed to nextDictEncodedVal is not one of the implemented variants, during packed dictionary decoding of rows (e.g. from timestampInt96ReaderPackedDictionaryDecodeDecodesRowsCorrectly).

Common situations: Reading legacy Hive/Spark 1.x/Impala-written Parquet files that store timestamps as INT96 with dictionary encoding, consumed via the Iceberg vectorized Arrow reader using an unimplemented decode mode.

Related errors


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