apache/iceberg · error · UnsupportedOperationException

Variant column only supports getVariant()

Error message

Variant column only supports getVariant()

What it means

VariantColumnVector wraps an Iceberg variant column for Spark's vectorized reader. Variants are not scalar values, so all typed scalar accessors (getBoolean, getByte, ...) are hard-wired to throw UnsupportedOperationException with 'Variant column only supports getVariant()'. Only getVariant()/getChild (value and metadata children) are meaningful. This error means Spark or user code tried to read a variant column as a plain boolean.

Solutions

  1. Access the value via getVariant()/variant_get(...) or cast the variant result in Spark SQL (e.g. CAST(col AS BOOLEAN) through variant_get) rather than reading the column as a scalar.
  2. If you own the calling code, check vector.dataType() instanceof VariantType and route to the variant child vectors (getChild(0)=value, getChild(1)=metadata) instead of calling getBoolean.
  3. Disable the vectorized reader for such reads (read.parquet.vectorization.enabled=false) as a workaround if a Spark expression incorrectly hits the scalar path.
  4. Upgrade Spark/Iceberg to versions with full variant expression support so plans never read variant columns as primitives.

Example fix

// before
boolean v = columnVector.getBoolean(rowId); // throws for variant columns
// after
ColumnVector variantVal = columnVector.getChild(0);
// decode variant value via variant metadata, or in SQL: variant_get(col, '$.field')
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isVariant = columnVector.dataType() instanceof org.apache.spark.sql.types.VariantType;

Type guard

boolean isVariantVector(ColumnVector cv) {
  return cv.dataType() instanceof org.apache.spark.sql.types.VariantType;
}

Try / catch

try {
  v = vector.getBoolean(rowId);
} catch (UnsupportedOperationException e) {
  // column is a variant: decode via getChild(0)/(1) or variant_get in SQL
}

Prevention

When it happens

Trigger: Spark's vectorized Parquet reader invokes getBoolean(rowId) on a ColumnVector whose dataType is VariantType — e.g. an expression or cast attempts to read the variant column as boolean instead of going through getVariant()/variant_get.

Common situations: Casting a variant column directly to boolean in Spark SQL; custom Spark data-source or expression code that reads columns generically by primitive type without handling VariantType; running an older Spark build whose vectorized reader does not know about variant columns.

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/00cbad89ff60413b. Report an issue: GitHub.

Appendix: source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/data/vectorized/VariantColumnVector.java:80

    return valueChild.isNullAt(rowId);
  }

  // getChild is what getVariant() calls: child(0) = value, child(1) = metadata
  @Override
  public ColumnVector getChild(int ordinal) {
    if (ordinal == 0) {
      return valueChild;
    } else if (ordinal == 1) {
      return metadataChild;
    }

    throw new IllegalArgumentException(
        "Variant column has only 2 children, got ordinal: " + ordinal);
  }

  @Override
  public boolean getBoolean(int rowId) {
    throw unsupported();
  }

  @Override
  public byte getByte(int rowId) {
    throw unsupported();
  }

  @Override
  public short getShort(int rowId) {
    throw unsupported();
  }

  @Override
  public int getInt(int rowId) {
    throw unsupported();
  }

  @Override

View on GitHub (pinned to 86d9c8fc54)