apache/iceberg · error · IllegalArgumentException

Expected one (and same) ORC type for list elements, got: {or

Error message

Expected one (and same) ORC type for list elements, got: {orcTypes}

What it means

SparkOrcValueWriters.ListWriter wraps an element writer and expects exactly one ORC TypeDescription describing the list's element type. If orcTypes.size() != 1 the ORC type tree does not match the expected list layout, so the constructor throws IllegalArgumentException to fail fast rather than reading the wrong child types.

Source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/data/SparkOrcValueWriters.java:137

  }

  private static class Decimal38Writer implements OrcValueWriter<Decimal> {

    @Override
    public void nonNullWrite(int rowId, Decimal decimal, ColumnVector output) {
      ((DecimalColumnVector) output)
          .vector[rowId].set(HiveDecimal.create(decimal.toJavaBigDecimal()));
    }
  }

  private static class ListWriter<T> implements OrcValueWriter<ArrayData> {
    private final OrcValueWriter<T> writer;
    private final SparkOrcWriter.FieldGetter<T> fieldGetter;

    @SuppressWarnings("unchecked")
    ListWriter(OrcValueWriter<T> writer, List<TypeDescription> orcTypes) {
      if (orcTypes.size() != 1) {
        throw new IllegalArgumentException(
            "Expected one (and same) ORC type for list elements, got: " + orcTypes);
      }
      this.writer = writer;
      this.fieldGetter =
          (SparkOrcWriter.FieldGetter<T>) SparkOrcWriter.createFieldGetter(orcTypes.get(0));
    }

    @Override
    public void nonNullWrite(int rowId, ArrayData value, ColumnVector output) {
      ListColumnVector cv = (ListColumnVector) output;
      // record the length and start of the list elements
      cv.lengths[rowId] = value.numElements();
      cv.offsets[rowId] = cv.childCount;
      cv.childCount = (int) (cv.childCount + cv.lengths[rowId]);
      // make sure the child is big enough
      growColumnVector(cv.child, cv.childCount);
      // Add each element
      for (int e = 0; e < cv.lengths[rowId]; ++e) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Pass only the element TypeDescription of the ORC list to ListWriter
  2. Verify the schema mapping produces one child type per list column
  3. Update Iceberg if the mismatch comes from a fixed mapping bug
  4. Inspect the ORC schema (TypeDescription.print()) to confirm the list layout

Example fix

// before
new ListWriter<>(elemWriter, record.getChildren())
// after
new ListWriter<>(elemWriter, record.getChildren().get(0).getChildren())
Defensive patterns

Strategy: try-catch

Validate before calling

List<TypeDescription> children = listType.getChildren();
if (children.size() != 1) {
  throw new IllegalStateException("List column must have exactly one element type, got: " + children.size());
}

Try / catch

try {
  new SparkOrcValueWriters.ListWriter<>(w, orcTypes);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("list elements")) { /* fix the orcTypes slice */ }
  else throw e;
}

Prevention

When it happens

Trigger: Building an ORC ListWriter with a malformed list of child TypeDescriptions — e.g. passing the struct's full child list instead of the list element type, or a corrupted/misaligned schema mapping.

Common situations: Bugs in ORC schema-to-writer mapping code; custom writer plumbing passing the wrong orcTypes slice; ORC files written with non-standard nested type layouts.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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