apache/iceberg · error · UnsupportedOperationException

Unsupported base type for decimal: ${primitive.getPrimitiveT

Error message

Unsupported base type for decimal: ${primitive.getPrimitiveTypeName()}

What it means

When reading Parquet, decimal columns can be physically stored as FIXED_LEN_BYTE_ARRAY, BINARY, INT64, or INT32. SparkParquetReaders' primitive() method throws UnsupportedOperationException if a DECIMAL-annotated column uses any other base physical type, since no decimal reader exists for it.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/data/SparkParquetReaders.java:271

          case DATE:
          case INT_64:
            return new UnboxedReader<>(desc);
          case TIMESTAMP_MICROS:
          case TIMESTAMP_MILLIS:
            return ParquetValueReaders.timestamps(desc);
          case DECIMAL:
            DecimalLogicalTypeAnnotation decimal =
                (DecimalLogicalTypeAnnotation) primitive.getLogicalTypeAnnotation();
            switch (primitive.getPrimitiveTypeName()) {
              case BINARY:
              case FIXED_LEN_BYTE_ARRAY:
                return new BinaryDecimalReader(desc, decimal.getScale());
              case INT64:
                return new LongDecimalReader(desc, decimal.getPrecision(), decimal.getScale());
              case INT32:
                return new IntegerDecimalReader(desc, decimal.getPrecision(), decimal.getScale());
              default:
                throw new UnsupportedOperationException(
                    "Unsupported base type for decimal: " + primitive.getPrimitiveTypeName());
            }
          case BSON:
            return new ParquetValueReaders.ByteArrayReader(desc);
          default:
            throw new UnsupportedOperationException(
                "Unsupported logical type: " + primitive.getOriginalType());
        }
      }

      switch (primitive.getPrimitiveTypeName()) {
        case FIXED_LEN_BYTE_ARRAY:
        case BINARY:
          if (expected != null && expected.typeId() == TypeID.UUID) {
            return new UUIDReader(desc);
          }
          return new ParquetValueReaders.ByteArrayReader(desc);
        case INT32:

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Rewrite the offending files with a standards-compliant writer (e.g. rewrite_data_files procedure).
  2. Check the Parquet footer to confirm the decimal column's physical type.
  3. Exclude or repair files written by the non-conforming producer before reading.
Defensive patterns

Strategy: validation

Validate before calling

ParquetMetadata meta = ParquetFileReader.readFooter(conf, path);
for (ColumnDescriptor cd : meta.getFileMetaData().getSchema().getColumns()) {
  OriginalType ot = cd.getPrimitiveType().getOriginalType();
  if (ot == OriginalType.DECIMAL) {
    Primitive p = cd.getPrimitiveType().getPrimitiveTypeName();
    if (p != FIXED_LEN_BYTE_ARRAY && p != BINARY && p != INT64 && p != INT32)
      throw new IllegalStateException("bad decimal base: " + cd.getPath());
  }
}

Try / catch

try {
  icebergTable.newScan().toSpark().load();
} catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Unsupported base type for decimal")) {
    // rewrite offending files via rewrite_data_files
  }
}

Prevention

When it happens

Trigger: Reading a Parquet file whose decimal column is stored on an unexpected physical type (e.g. FLOAT/DOUBLE or INT96 with DECIMAL logical type) — typically from files written by non-conforming tools.

Common situations: Parquet files produced by legacy or buggy writers storing decimals with unusual physical representations; corrupted schema metadata; mixing files from different writers in one table.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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