{"record":{"id":"e08b07c9aa005a22","repo":"apache/iceberg","slug":"variant-column-only-supports-getvariant-e08b07","errorCode":null,"errorMessage":"Variant column only supports getVariant()","messagePattern":"Variant column only supports getVariant\\(\\)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/data/vectorized/VariantColumnVector.java","lineNumber":80,"sourceCode":"    return valueChild.isNullAt(rowId);\n  }\n\n  // getChild is what getVariant() calls: child(0) = value, child(1) = metadata\n  @Override\n  public ColumnVector getChild(int ordinal) {\n    if (ordinal == 0) {\n      return valueChild;\n    } else if (ordinal == 1) {\n      return metadataChild;\n    }\n\n    throw new IllegalArgumentException(\n        \"Variant column has only 2 children, got ordinal: \" + ordinal);\n  }\n\n  @Override\n  public boolean getBoolean(int rowId) {\n    throw unsupported();\n  }\n\n  @Override\n  public byte getByte(int rowId) {\n    throw unsupported();\n  }\n\n  @Override\n  public short getShort(int rowId) {\n    throw unsupported();\n  }\n\n  @Override\n  public int getInt(int rowId) {\n    throw unsupported();\n  }\n\n  @Override","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/data/vectorized/VariantColumnVector.java#L62-L98","documentation":"VariantColumnVector models a Spark VARIANT column as two child vectors (value at ordinal 0, metadata at ordinal 1). getBoolean() has no meaningful mapping to that pair, so it throws UnsupportedOperationException — only getVariant()/getChild are supported for variant columns.","triggerScenarios":"Calling getBoolean(rowId) on a variant-typed column in a ColumnarBatch produced by Iceberg's vectorized reader; commonly from generic per-row extraction code or an engine that resolved a variant-to-boolean cast to the raw column vector.","commonSituations":"Custom code reading all columns of a batch by primitive accessors; queries forcing variant-to-boolean casts; compatibility shims porting Iceberg batches into engines that expect plain typed vectors.","solutions":["Read the value with getVariant(rowId) instead","Cast the variant explicitly via variant functions in Spark rather than in the column vector","Add a VariantType guard in code that iterates batch columns"],"exampleFix":"// before\nboolean b = columnVector.getBoolean(rowId);\n// after\nObject variant = columnVector.getVariant(rowId);","handlingStrategy":"type-guard","validationCode":"if (!(dataType instanceof org.apache.spark.sql.types.VariantType)) { return columnVector.getBoolean(rowId); }","typeGuard":"boolean canGetBoolean(ColumnVector cv, org.apache.spark.sql.types.DataType t) { return !(t instanceof org.apache.spark.sql.types.VariantType); }","tryCatchPattern":"try { b = cv.getBoolean(rowId); } catch (UnsupportedOperationException e) { if (e.getMessage() != null && e.getMessage().contains(\"only supports getVariant\")) { b = extractBoolean(cv.getVariant(rowId)); } else { throw e; } }","preventionTips":["Check the batch schema per column before calling typed accessors","Use variant functions for scalar extraction instead of casting columns","Avoid generic readers that assume all vectors are primitive-typed"],"tags":["spark","vectorized-reader","variant","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}