apache/iceberg · error · java.lang.UnsupportedOperationException

Not implemented for variant

Error message

Not implemented for variant

What it means

The SparkTypeToIcebergType visitor's default variant() hook has no implementation; any concrete visitor that does not override it will throw when the schema contains a Spark VariantType column. This is an extension-point guard: subclass visitors must handle variant or reject it explicitly.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/SparkTypeVisitor.java:64

          visit(((MapType) type).keyType(), visitor),
          visit(((MapType) type).valueType(), visitor));

    } else if (type instanceof ArrayType) {
      return visitor.array((ArrayType) type, visit(((ArrayType) type).elementType(), visitor));

    } else if (type instanceof VariantType) {
      return visitor.variant((VariantType) type);

    } else if (type instanceof UserDefinedType) {
      throw new UnsupportedOperationException("User-defined types are not supported");

    } else {
      return visitor.atomic(type);
    }
  }

  public T variant(VariantType variant) {
    throw new UnsupportedOperationException("Not implemented for variant");
  }

  public T struct(StructType struct, List<T> fieldResults) {
    return null;
  }

  public T field(StructField field, T typeResult) {
    return null;
  }

  public T array(ArrayType array, T elementResult) {
    return null;
  }

  public T map(MapType map, T keyResult, T valueResult) {
    return null;
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Override variant(VariantType variant) in your visitor subclass and return the desired mapping (e.g. Types.VariantType.get())
  2. Reject variant columns earlier by filtering them out of the schema before applying the visitor
  3. Do not use the default visitor directly; subclass it and handle all relevant types

Example fix

// before
class MyVisitor extends SparkTypeVisitor<Type> { }
// after
class MyVisitor extends SparkTypeVisitor<Type> {
  @Override
  public Type variant(VariantType variant) {
    return Types.VariantType.get();
  }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// before applying visitor
boolean hasVariant = false;
for (StructField f : sparkSchema.fields()) {
  if (f.dataType().typeName().equalsIgnoreCase("variant")) { hasVariant = true; break; }
}
if (hasVariant) throw new IllegalArgumentException("Variant columns require a visitor that implements variant()");

Type guard

static boolean hasVariantColumn(StructType schema) {
  for (StructField f : schema.fields()) {
    if (f.dataType() instanceof org.apache.spark.sql.types.VariantType) return true;
  }
  return false;
}

Try / catch

try { visitor.apply(type) } catch (UnsupportedOperationException e) { if (e.getMessage().contains("Not implemented for variant")) { /* fallback: drop/reject variant columns */ } else throw e; }

Prevention

When it happens

Trigger: A custom TypeVisitor subclass (extending SparkTypeVisitor) is applied to a Spark schema containing a VariantType column (Spark 4.x variant type) and the subclass does not override variant(VariantType).

Common situations: Upgrading to Spark 4.x where variant columns appear in schemas read from Parquet or defined via VARIANT literal; authors of custom type visitors forgetting to implement the new variant callback.

Related errors


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