apache/iceberg · error · IllegalStateException

Unknown type for binary field. Type name: +…

Error message

Unknown type for binary field. Type name: + bytes.getClass().getName()

What it means

StructInternalRow.getBinaryInternal wraps the underlying value of an Iceberg binary field for Spark and expects it to be either a ByteBuffer or a byte[]. If the stored value is any other Java type, it cannot be converted to a byte array, so an IllegalStateException is thrown. This is an internal invariant violation: the in-memory value does not match the declared binary column type.

Solutions

  1. Inspect the actual class name in the message and fix the producer so it stores byte[] or ByteBuffer for binary fields.
  2. Convert the value before building the row: ByteBuffers.toByteArray(buffer) for buffers, or an explicit encoding (e.g. String.getBytes(UTF_8)) for other types.
  3. Check for an intermediate transform (custom InternalRow wrapper or Spark version migration) changing the stored representation.
  4. Re-read the same rows with a vanilla Spark Iceberg reader to determine whether the source data or your code path is at fault.

Example fix

// before
row.set(ordinal, someString); // arbitrary object in a binary column
// after
if (!(value instanceof ByteBuffer) && !(value instanceof byte[])) {
  throw new IllegalArgumentException("Expected ByteBuffer or byte[], got " + value.getClass());
}
row.set(ordinal, value);
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = row.get(ordinal);
if (v != null && !(v instanceof ByteBuffer) && !(v instanceof byte[])) {
  throw new IllegalStateException("Unexpected binary representation: " + v.getClass());
}

Type guard

static boolean isBinaryRepr(Object v) {
  return v == null || v instanceof ByteBuffer || v instanceof byte[];
}

Try / catch

try {
  byte[] b = structRow.getBinary(ordinal);
} catch (IllegalStateException e) {
  // parse class name from message, quarantine the record, re-encode from source
}

Prevention

When it happens

Trigger: Calling getBinary(ordinal) on a StructInternalRow whose backing value for that ordinal is neither ByteBuffer nor byte[] — e.g. custom data-source integrations, reflection-based row construction that bypassed the expected conversion, or upstream code that stored a String or wrapper object in a binary column.

Common situations: Custom Spark readers/writers feeding Iceberg rows with the wrong in-memory representation; regressions after a Spark or Iceberg upgrade where a producer changed its binary encoding; corrupt values from a misbehaving extension that mutated row data.

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/957e43816ae2f13c. Report an issue: GitHub.

Appendix: source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java:199

    CharSequence seq = struct.get(ordinal, CharSequence.class);
    return UTF8String.fromString(seq.toString());
  }

  @Override
  public byte[] getBinary(int ordinal) {
    return isNullAt(ordinal) ? null : getBinaryInternal(ordinal);
  }

  private byte[] getBinaryInternal(int ordinal) {
    Object bytes = struct.get(ordinal, Object.class);

    // should only be either ByteBuffer or byte[]
    if (bytes instanceof ByteBuffer) {
      return ByteBuffers.toByteArray((ByteBuffer) bytes);
    } else if (bytes instanceof byte[]) {
      return (byte[]) bytes;
    } else {
      throw new IllegalStateException(
          "Unknown type for binary field. Type name: " + bytes.getClass().getName());
    }
  }

  @Override
  public CalendarInterval getInterval(int ordinal) {
    throw new UnsupportedOperationException("Unsupported type: interval");
  }

  @Override
  public InternalRow getStruct(int ordinal, int numFields) {
    return isNullAt(ordinal) ? null : getStructInternal(ordinal);
  }

  private InternalRow getStructInternal(int ordinal) {
    return new StructInternalRow(
        type.fields().get(ordinal).type().asStructType(), struct.get(ordinal, StructLike.class));
  }

View on GitHub (pinned to 86d9c8fc54)