apache/iceberg · error · UnsupportedOperationException

Variants must be read using read(VariantMetadata)

Error message

Variants must be read using read(VariantMetadata)

What it means

VariantValueReader extends ParquetValueReader but Variants are not read in the normal read(reuse) style. The default read(VariantValue reuse) method deliberately throws UnsupportedOperationException because variant values require VariantMetadata context; callers must use read(VariantMetadata) instead.

Solutions

  1. Use read(VariantMetadata metadata) and supply the variant metadata obtained from the table/manifest
  2. Ensure the generic reader path dispatches to VariantValueReader specially instead of calling read(reuse)
  3. Upgrade or patch the consuming engine integration to support variants

Example fix

// before: generic read
VariantValue v = variantReader.read(null);
// after: provide metadata
VariantValue v = variantReader.read(variantMetadata);
Defensive patterns

Strategy: type-guard

Validate before calling

if (reader instanceof ParquetVariantReaders.VariantValueReader) {
  // must call read(VariantMetadata), not read(reuse)
}

Type guard

VariantValue readVariant(ParquetValueReader<?> reader, VariantMetadata md) {
  if (reader instanceof ParquetVariantReaders.VariantValueReader) {
    return ((ParquetVariantReaders.VariantValueReader) reader).read(md);
  }
  throw new IllegalArgumentException("Not a variant reader");
}

Try / catch

try {
  v = reader.read(reuse);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("Variants must be read using read(VariantMetadata)")) {
    v = ((VariantValueReader) reader).read(variantMetadata);
  } else throw e;
}

Prevention

When it happens

Trigger: Invoking read(reuse) on any VariantValueReader — typically from generic Parquet reader code that treats the variant column like an ordinary primitive, or from copied reader pipelines that call the base interface method.

Common situations: Wiring a variant reader into a generic column-reader path that only knows ParquetValueReader.read(reuse); custom engine adapters calling the wrong overload; frameworks iterating readers polymorphically without variant support.

Related errors


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

Appendix: source

Thrown at parquet/src/main/java/org/apache/iceberg/parquet/ParquetVariantReaders.java:49

import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
import org.apache.iceberg.variants.PhysicalType;
import org.apache.iceberg.variants.ShreddedObject;
import org.apache.iceberg.variants.ValueArray;
import org.apache.iceberg.variants.Variant;
import org.apache.iceberg.variants.VariantMetadata;
import org.apache.iceberg.variants.VariantObject;
import org.apache.iceberg.variants.VariantValue;
import org.apache.iceberg.variants.Variants;
import org.apache.parquet.column.ColumnDescriptor;
import org.apache.parquet.column.page.PageReadStore;

public class ParquetVariantReaders {
  private ParquetVariantReaders() {}

  public interface VariantValueReader extends ParquetValueReader<VariantValue> {
    @Override
    default VariantValue read(VariantValue reuse) {
      throw new UnsupportedOperationException("Variants must be read using read(VariantMetadata)");
    }

    /** Reads a variant value */
    VariantValue read(VariantMetadata metadata);
  }

  private static final VariantValue MISSING = null;

  @SuppressWarnings("unchecked")
  public static ParquetValueReader<Variant> variant(
      ParquetValueReader<?> metadata, ParquetValueReader<?> value) {
    return new VariantReader(
        (ParquetValueReader<VariantMetadata>) metadata, (VariantValueReader) value);
  }

  public static ParquetValueReader<VariantMetadata> metadata(ColumnDescriptor desc) {
    return new VariantMetadataReader(desc);
  }

View on GitHub (pinned to 86d9c8fc54)