apache/iceberg · error · IllegalStateException

Unknown type for binary field. Type name: ${bytes.getClass()

Error message

Unknown type for binary field. Type name: ${bytes.getClass().getName()}

What it means

getBinaryInternal extracts binary column values and only accepts ByteBuffer or byte[] from the underlying StructLike. Any other object type (String, Array[Byte] wrappers, custom types) throws IllegalStateException reporting the found class. It backs getBinary, getGeometry, getGeography, and binary view getters.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java:195

    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)

Solutions

  1. Ensure binary-typed fields store ByteBuffer or byte[] in the StructLike
  2. Convert before read: wrap byte[] in ByteBuffer or copy the ByteBuffer via ByteBuffers.toByteArray yourself
  3. Use the message's class name to locate the offending producer and fix its conversion
  4. If you consume via getBinary, defensively fetch with get(ordinal, null) and normalize

Example fix

// before
byte[] b = row.getBinary(ordinal); // value is String
// after
Object raw = row.get(ordinal, null);
byte[] b = raw instanceof String
    ? ((String) raw).getBytes(StandardCharsets.UTF_8)
    : row.getBinary(ordinal);
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

boolean isBinaryCompatible(Object v) { return v instanceof ByteBuffer || v instanceof byte[]; }

Try / catch

try {
  return row.getBinary(ordinal);
} catch (IllegalStateException e) {
  throw new IllegalStateException("Binary field held unexpected Java type", e);
}

Prevention

When it happens

Trigger: A binary/geometry/geography column whose StructLike value is neither ByteBuffer nor byte[] — e.g. a custom producer storing UTF8String or a deserialization bug producing a wrong wrapper type.

Common situations: Custom readers or test fixtures populating binary fields with Strings; ORM/record adapters converting binary to unexpected Java types; geometry column values built by hand.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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