apache/iceberg · error · UnsupportedOperationException

Unsupported base type for decimal:

Error message

Unsupported base type for decimal: 

What it means

When a column is dictionary-encoded, the factory builds a Dictionary*Accessor whose backing type must match the decimal's Parquet base type (FIXED_LEN_BYTE_ARRAY, INT64, or INT32). A decimal stored with any other base physical type has no dictionary accessor implementation, so the default branch throws this error.

Source

Thrown at arrow/src/main/java/org/apache/iceberg/arrow/vectorized/GenericArrowVectorAccessorFactory.java:153

        case INT_64:
        case TIME_MICROS:
        case TIMESTAMP_MILLIS:
        case TIMESTAMP_MICROS:
          return new DictionaryLongAccessor<>((IntVector) vector, dictionary);
        case DECIMAL:
          switch (primitive.getPrimitiveTypeName()) {
            case BINARY:
            case FIXED_LEN_BYTE_ARRAY:
              return new DictionaryDecimalBinaryAccessor<>(
                  (IntVector) vector, dictionary, decimalFactorySupplier.get());
            case INT64:
              return new DictionaryDecimalLongAccessor<>(
                  (IntVector) vector, dictionary, decimalFactorySupplier.get());
            case INT32:
              return new DictionaryDecimalIntAccessor<>(
                  (IntVector) vector, dictionary, decimalFactorySupplier.get());
            default:
              throw new UnsupportedOperationException(
                  "Unsupported base type for decimal: " + primitive.getPrimitiveTypeName());
          }
        default:
          throw new UnsupportedOperationException(
              "Unsupported logical type: " + primitive.getOriginalType());
      }
    } else {
      switch (primitive.getPrimitiveTypeName()) {
        case FIXED_LEN_BYTE_ARRAY:
        case BINARY:
          return new DictionaryBinaryAccessor<>(
              (IntVector) vector, dictionary, stringFactorySupplier.get());
        case FLOAT:
          return new DictionaryFloatAccessor<>((IntVector) vector, dictionary);
        case INT64:
          return new DictionaryLongAccessor<>((IntVector) vector, dictionary);
        case INT96:
          // Impala & Spark used to write timestamps as INT96 by default. For backwards

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Rewrite/compact the data with standard Iceberg writers so decimals use the canonical physical types
  2. Fall back to the non-vectorized (row) reader for such files
  3. Inspect the Parquet schema (parquet-tools) to confirm the decimal's physical type and fix at write time
Defensive patterns

Strategy: fallback

Validate before calling

LogicalTypeAnnotation ann = primitive.getLogicalTypeAnnotation(); if (ann instanceof DecimalLogicalTypeAnnotation && !EnumSet.of(FIXED_LEN_BYTE_ARRAY, INT64, INT32).contains(primitive.getPrimitiveTypeName())) { useRowReader(); }

Try / catch

try { accessor = factory.getVectorAccessor(holder); } catch (UnsupportedOperationException e) { accessor = rowBasedAccessor(holder); }

Prevention

When it happens

Trigger: Reading a dictionary-encoded Parquet decimal column whose primitive base type is not FIXED_LEN_BYTE_ARRAY/INT64/INT32 (e.g. an unexpected physical encoding produced by a non-standard writer), via getVectorAccessor on a VectorHolder with a dictionary.

Common situations: Files written by third-party/older Parquet writers using unusual physical types for decimal logical type; mixed-writer datasets where encoding metadata doesn't match Iceberg's expectations.

Related errors


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