apache/iceberg · error · UnsupportedOperationException

Field %d has unsupported field type: %s

Error message

Field %d has unsupported field type: %s

What it means

SortKeySerializer.serialize() flattens each SortKey field into the DataOutputView by switching on the Iceberg type id. Numeric/text/temporal/primitive types are supported, but STRUCT, MAP, LIST (and the default arm) are not — the SortKey representation is a flattened struct without nested collections, so serialize throws UnsupportedOperationException identifying the field id and type. The table's sort order contains a column with a nested/complex type.

Source

Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/sink/shuffle/SortKeySerializer.java:197

        case FIXED:
        case BINARY:
          byte[] bytes = record.get(i, ByteBuffer.class).array();
          target.writeInt(bytes.length);
          target.write(bytes);
          break;
        case DECIMAL:
          BigDecimal decimal = record.get(i, BigDecimal.class);
          byte[] decimalBytes = decimal.unscaledValue().toByteArray();
          target.writeInt(decimalBytes.length);
          target.write(decimalBytes);
          target.writeInt(decimal.scale());
          break;
        case STRUCT:
        case MAP:
        case LIST:
        default:
          // SortKey transformation is a flattened struct without list and map
          throw new UnsupportedOperationException(
              String.format(
                  Locale.ROOT, "Field %d has unsupported field type: %s", fieldId, typeId));
      }
    }
  }

  @Override
  public SortKey deserialize(DataInputView source) throws IOException {
    // copying is a little faster than constructing a new SortKey object
    SortKey deserialized = lazySortKey().copy();
    deserialize(deserialized, source);
    return deserialized;
  }

  @Override
  public SortKey deserialize(SortKey reuse, DataInputView source) throws IOException {
    Preconditions.checkArgument(
        reuse.size() == size,

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Rewrite the table sort order to use only primitive-typed columns (no struct/map/list).
  2. Sort on a primitive component of the nested field (e.g. a top-level string/long extracted by the upstream job) instead of the nested column.
  3. Change write.distribution.mode to 'hash' (on a primitive key) or 'none' to avoid serializing SortKeys.
  4. Check the schema with a tool like DESCRIBE TABLE and confirm each sort column's type before enabling sorted writes.

Example fix

// before
ALTER TABLE t WRITE ORDERED BY tags;  -- tags is list<string>
// after
ALTER TABLE t WRITE ORDERED BY user_id, created_at;
Defensive patterns

Strategy: validation

Validate before calling

table.sortOrder().fields().forEach(f -> {
  Type t = schema.findType(f.sourceId());
  Preconditions.checkArgument(t.isPrimitiveType(),
      "Sort column %s must be primitive, found %s", f.sourceId(), t);
});

Type guard

boolean sortKeySafe(Type t) {
  return t.isPrimitiveType();
}

Try / catch

try {
  serializer.serialize(sortKey, view);
} catch (UnsupportedOperationException e) {
  LOG.error("Sort order uses unsupported nested column; fix table sort order", e);
  throw e;
}

Prevention

When it happens

Trigger: Configuring a table sort order that includes a struct, map, or list column, then running a sorted write (write.distribution.mode=range or sorted write) in Flink so SortKey values must be serialized for the shuffle or sketch.

Common situations: Defining ALTER TABLE ... ORDER BY on a column of type map/list/struct by mistake; sort order inherited from Spark where nested sort keys behave differently; schema evolution adding a nested column into the sort spec.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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