apache/iceberg · error · IllegalArgumentException

Variant column has only 2 children, got ordinal

Error message

Variant column has only 2 children, got ordinal: ${ordinal}

What it means

A Spark Variant column vector is composed of exactly two children: value (ordinal 0) and metadata (ordinal 1). getChild is called by the engine to descend into struct-like children; any ordinal outside 0..1 indicates the engine is treating the variant vector as a struct with more fields than it has, so the vector throws IllegalArgumentException.

Solutions

  1. Verify the Spark version matches the icebberg-spark-4.1 module expectations (variant support requires recent Spark 4.x)
  2. Don't index VariantColumnVector as a struct beyond its two children; use getVariant(rowId) style access instead
  3. Check the physical schema wasn't altered so the variant column resolves as a struct with extra fields

Example fix

// before
ColumnVector child = variantVector.getChild(2);
// after
if (ordinal < variantVector.getNumChildren()) {
  ColumnVector child = variantVector.getChild(ordinal);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (ordinal < 0 || ordinal >= 2) {
  throw new IllegalArgumentException("VariantColumnVector exposes only ordinals 0 (value) and 1 (metadata)");
}

Type guard

boolean isValidVariantChildOrdinal(int ordinal) { return ordinal == 0 || ordinal == 1; }

Try / catch

try {
  ColumnVector child = variantVector.getChild(ordinal);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Variant column has only 2 children")) {
    throw new IllegalStateException("Wrong ordinal for variant child; use 0=value, 1=metadata", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling getChild(ordinal) on VariantColumnVector with ordinal >= 2, typically from a Spark plan that misinterprets the variant column's internal layout or indexes a wrong field position.

Common situations: Version drift between Spark's VariantVal handling and Iceberg's variant vector implementation; custom readers/code touching the variant column vector internals with wrong ordinals.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

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

  public int numNulls() {
    return valueChild.numNulls();
  }

  @Override
  public boolean isNullAt(int rowId) {
    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();
  }

View on GitHub (pinned to 86d9c8fc54)