{"record":{"id":"957e43816ae2f13c","repo":"apache/iceberg","slug":"unknown-type-for-binary-field-type-name-bytes-957e43","errorCode":null,"errorMessage":"Unknown type for binary field. Type name: + bytes.getClass().getName()","messagePattern":"Unknown type for binary field\\. Type name: \\+ bytes\\.getClass\\(\\)\\.getName\\(\\)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java","lineNumber":199,"sourceCode":"    CharSequence seq = struct.get(ordinal, CharSequence.class);\n    return UTF8String.fromString(seq.toString());\n  }\n\n  @Override\n  public byte[] getBinary(int ordinal) {\n    return isNullAt(ordinal) ? null : getBinaryInternal(ordinal);\n  }\n\n  private byte[] getBinaryInternal(int ordinal) {\n    Object bytes = struct.get(ordinal, Object.class);\n\n    // should only be either ByteBuffer or byte[]\n    if (bytes instanceof ByteBuffer) {\n      return ByteBuffers.toByteArray((ByteBuffer) bytes);\n    } else if (bytes instanceof byte[]) {\n      return (byte[]) bytes;\n    } else {\n      throw new IllegalStateException(\n          \"Unknown type for binary field. Type name: \" + bytes.getClass().getName());\n    }\n  }\n\n  @Override\n  public CalendarInterval getInterval(int ordinal) {\n    throw new UnsupportedOperationException(\"Unsupported type: interval\");\n  }\n\n  @Override\n  public InternalRow getStruct(int ordinal, int numFields) {\n    return isNullAt(ordinal) ? null : getStructInternal(ordinal);\n  }\n\n  private InternalRow getStructInternal(int ordinal) {\n    return new StructInternalRow(\n        type.fields().get(ordinal).type().asStructType(), struct.get(ordinal, StructLike.class));\n  }","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/StructInternalRow.java#L181-L217","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the actual class name in the message and fix the producer so it stores byte[] or ByteBuffer for binary fields.","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.","Check for an intermediate transform (custom InternalRow wrapper or Spark version migration) changing the stored representation.","Re-read the same rows with a vanilla Spark Iceberg reader to determine whether the source data or your code path is at fault."],"exampleFix":"// before\nrow.set(ordinal, someString); // arbitrary object in a binary column\n// after\nif (!(value instanceof ByteBuffer) && !(value instanceof byte[])) {\n  throw new IllegalArgumentException(\"Expected ByteBuffer or byte[], got \" + value.getClass());\n}\nrow.set(ordinal, value);","handlingStrategy":"type-guard","validationCode":"Object v = row.get(ordinal);\nif (v != null && !(v instanceof ByteBuffer) && !(v instanceof byte[])) {\n  throw new IllegalStateException(\"Unexpected binary representation: \" + v.getClass());\n}","typeGuard":"static boolean isBinaryRepr(Object v) {\n  return v == null || v instanceof ByteBuffer || v instanceof byte[];\n}","tryCatchPattern":"try {\n  byte[] b = structRow.getBinary(ordinal);\n} catch (IllegalStateException e) {\n  // parse class name from message, quarantine the record, re-encode from source\n}","preventionTips":["Always build rows with byte[] or ByteBuffer for Iceberg BinaryType columns.","Round-trip binary columns through StructInternalRow in integration tests.","Centralize row construction in one factory so conversions are applied consistently."],"tags":["spark","internal-row","binary","illegal-state"],"backgroundTag":"internal-invariant-violation","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"}