apache/iceberg · error · UnsupportedOperationException

Not supported yet.

Error message

Not supported yet.

What it means

StructRowData wraps an Iceberg StructLike as a Flink RowData. Its getRawValue method, which would return an opaque RawValueData view of a field, is simply not implemented and always throws UnsupportedOperationException. Callers must use the typed accessors (getInt, getLong, getBinary, etc.) instead.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/data/StructRowData.java:214

        LocalDateTime ldt = (LocalDateTime) timeVal;
        return TimestampData.fromEpochMillis(
            ldt.toInstant(ZoneOffset.UTC).toEpochMilli(), ldt.getNano() % 1_000_000);
      } else if (timeVal instanceof Long) {
        long timeLong = (Long) timeVal;
        return TimestampData.fromEpochMillis(
            Math.floorDiv(timeLong, 1_000_000L), (int) Math.floorMod(timeLong, 1_000_000L));
      } else {
        throw new IllegalStateException("Unknown type for timestamp_ns: " + timeVal.getClass());
      }
    }
    long timeLong = getLong(pos);
    return TimestampData.fromEpochMillis(
        Math.floorDiv(timeLong, 1000L), (int) Math.floorMod(timeLong, 1000L) * 1000);
  }

  @Override
  public <T> RawValueData<T> getRawValue(int pos) {
    throw new UnsupportedOperationException("Not supported yet.");
  }

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

  private byte[] getBinaryInternal(int pos) {
    Object bytes = struct.get(pos, 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 if (bytes instanceof UUID) {
      UUID uuid = (UUID) bytes;
      ByteBuffer bb = ByteBuffer.allocate(16);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Rewrite the calling code to use typed accessors (isNullAt, getInt, getLong, getRow, getArray, getMap, getBinary) on the StructRowData instead of getRawValue.
  2. Convert the value via the Iceberg Flink converters (FlinkSchemaUtil / FlinkValueReaders path) to obtain a concrete typed value rather than raw bytes.
  3. If raw access is genuinely required, materialize the struct into a GenericRowData (which supports getRawValue) before passing it to the code that calls getRawValue.

Example fix

// before
RawValueData<?> raw = rowData.getRawValue(pos);
// after
Object field = rowData.isNullAt(pos) ? null : convertTypedField(rowData, pos, fieldType); // use typed accessor per LogicalType
Defensive patterns

Strategy: type-guard

Validate before calling

// before calling getRawValue
if (rowData instanceof org.apache.iceberg.flink.data.StructRowData) {
  throw new IllegalArgumentException("StructRowData does not support getRawValue; use typed accessors");
}

Type guard

boolean supportsRaw(RowData rd) { return !(rd instanceof org.apache.iceberg.flink.data.StructRowData); }

Try / catch

try { return rowData.getRawValue(pos); } catch (UnsupportedOperationException e) { return typedFallback(rowData, pos); }

Prevention

When it happens

Trigger: Calling RowData.getRawValue(pos) on a RowData produced by Iceberg's Flink data adapters (e.g. reading an Iceberg table's struct column as RowData), typically when a Flink codec/serializer or user function requests raw binary access to a field.

Common situations: Flink internal machinery or a UDF that optimizes by reading RawValueData from any RowData encounters a StructRowData; code that generically reads RowData fields assuming all implementations support raw access.

Related errors


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