{"record":{"id":"ca9818df31d9d0bb","repo":"apache/iceberg","slug":"unsupported-value-for-variant-in-structinternalrow","errorCode":null,"errorMessage":"Unsupported value for VARIANT in StructInternalRow: ${value.getClass()}","messagePattern":"Unsupported value for VARIANT in StructInternalRow: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java","lineNumber":374,"sourceCode":"        throw new UnsupportedOperationException(\"Unsupported array element type: \" + elementType);\n    }\n  }\n\n  private static VariantVal toVariantVal(Object value) {\n    if (value instanceof Variant) {\n      Variant variant = (Variant) value;\n      byte[] metadataBytes = new byte[variant.metadata().sizeInBytes()];\n      ByteBuffer metadataBuffer = ByteBuffer.wrap(metadataBytes).order(ByteOrder.LITTLE_ENDIAN);\n      variant.metadata().writeTo(metadataBuffer, 0);\n\n      byte[] valueBytes = new byte[variant.value().sizeInBytes()];\n      ByteBuffer valueBuffer = ByteBuffer.wrap(valueBytes).order(ByteOrder.LITTLE_ENDIAN);\n      variant.value().writeTo(valueBuffer, 0);\n\n      return new VariantVal(valueBytes, metadataBytes);\n    }\n\n    throw new UnsupportedOperationException(\n        \"Unsupported value for VARIANT in StructInternalRow: \" + value.getClass());\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  private <T> GenericArrayData fillArray(\n      Collection<?> values, Function<Object[], BiConsumer<Integer, T>> makeSetter) {\n    Object[] array = new Object[values.size()];\n    BiConsumer<Integer, T> setter = makeSetter.apply(array);\n\n    int index = 0;\n    for (Object value : values) {\n      if (value == null) {\n        array[index] = null;\n      } else {\n        setter.accept(index, (T) value);\n      }\n\n      index += 1;","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java#L356-L392","documentation":"toVariantVal converts a VARIANT column's in-memory value into Spark's VariantVal, accepting Iceberg Variant instances (and null). Any other Java class triggers an UnsupportedOperationException naming the unexpected class — the stored representation does not match what the Iceberg variant machinery produces.","triggerScenarios":"Calling getVariant(ordinal) or converting an array of variants on a StructInternalRow where the VARIANT column's value is neither a Variant nor null — e.g. a custom integration stored raw byte[]/String in a variant column, or mixed Iceberg versions deserialized variants differently.","commonSituations":"Third-party writers putting non-Variant objects into variant columns; writer/reader Iceberg version mismatch around variant materialization; custom data-source integrations bypassing variant encoding.","solutions":["Fix the producer so VARIANT columns hold proper org.apache.iceberg.variant.Variant instances.","Align the Iceberg reader runtime and producing writer versions for variant support.","If values arrive as raw bytes, reconstruct the Variant from metadata+value buffers before inserting into the row.","Use the class name in the message to locate which pipeline stage stored the wrong representation."],"exampleFix":"// before\nrow.set(ordinal, rawMetadataBytes); // wrong: byte[] stored in VARIANT column\n// after\nVariant variant = Variants.create(metadataBuffer, valueBuffer);\nrow.set(ordinal, variant);","handlingStrategy":"type-guard","validationCode":"Object v = row.get(ordinal);\nif (v != null && !(v instanceof Variant)) {\n  throw new IllegalStateException(\"VARIANT column holds non-Variant: \" + v.getClass());\n}","typeGuard":"static boolean isVariantValue(Object v) {\n  return v == null || v instanceof Variant;\n}","tryCatchPattern":"try {\n  VariantVal val = structRow.getVariant(ordinal);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"VARIANT\")) {\n    // decode raw bytes into a Variant, then retry\n  } else throw e;\n}","preventionTips":["Only insert org.apache.iceberg.variant.Variant instances into VARIANT columns.","Align writer and reader Iceberg versions where variant support is involved.","Unit-test variant round-trips through StructInternalRow in custom integrations."],"tags":["spark","variant","type-mismatch","internal-row"],"backgroundTag":"type-mismatch","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}