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
- 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.
- 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.
- Disable the vectorized reader for such reads (read.parquet.vectorization.enabled=false) as a workaround if a Spark expression incorrectly hits the scalar path.
- 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
- Check dataType() for VariantType before calling any scalar getter on a ColumnVector
- Use variant_get()/typed casts in Spark SQL rather than reading variant columns directly
- Keep Spark and Iceberg versions aligned on variant vectorized-read support
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
- Variant column only supports getVariant()
- Not implemented for variant
- Unsupported type - map
- Unsupported type - short
- Variant column only supports getVariant()
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();
}
@OverrideView on GitHub (pinned to 86d9c8fc54)