apache/iceberg · error · UnsupportedOperationException

Avro format doesn't support non-string as key type of map. T

Error message

Avro format doesn't support non-string as key type of map. The key type is: <keyType.asSummaryString()>

What it means

extractValueTypeToAvroMap converts a Flink MAP/MULTISET value type for Avro. Avro maps require string keys, so any key type not in CHARACTER_STRING family is rejected with UnsupportedOperationException.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/formats/avro/typeutils/AvroSchemaConverter.java:611

        throw new UnsupportedOperationException(
            "Unsupported to derive Schema for type: " + logicalType);
    }
  }

  public static LogicalType extractValueTypeToAvroMap(LogicalType type) {
    LogicalType keyType;
    LogicalType valueType;
    if (type instanceof MapType) {
      MapType mapType = (MapType) type;
      keyType = mapType.getKeyType();
      valueType = mapType.getValueType();
    } else {
      MultisetType multisetType = (MultisetType) type;
      keyType = multisetType.getElementType();
      valueType = new IntType();
    }
    if (!keyType.is(LogicalTypeFamily.CHARACTER_STRING)) {
      throw new UnsupportedOperationException(
          "Avro format doesn't support non-string as key type of map. "
              + "The key type is: "
              + keyType.asSummaryString());
    }
    return valueType;
  }

  /** Returns schema with nullable true. */
  private static Schema nullableSchema(Schema schema) {
    return schema.isNullable()
        ? schema
        : Schema.createUnion(SchemaBuilder.builder().nullType(), schema);
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Cast map keys to STRING before conversion: MAP_CAST via SQL `MAP_FROM_ENTRIES` or rebuild the map with CAST(key AS STRING).
  2. Restructure the data as an ARRAY<ROW<key,value>> if non-string keys are required.
  3. Use a non-Avro serialization format (e.g. Avro with schema adaptation via a custom converter) if string keys are impossible.

Example fix

// before: MAP<INT, STRING> fails
MapType t = new MapType(new IntType(), new StringType());

// after: string keys
MapType t = new MapType(new StringType(), new StringType());
// SQL: SELECT MAP(key_str, val) FROM (SELECT CAST(k AS STRING) AS key_str, v AS val FROM m),
Defensive patterns

Strategy: validation

Validate before calling

// verify map key type is string-like before conversion
LogicalType keyType = type instanceof MapType
    ? ((MapType) type).getKeyType()
    : ((MultisetType) type).getElementType();
if (!keyType.is(LogicalTypeFamily.CHARACTER_STRING)) {
    throw new IllegalArgumentException("Map keys must be string-like for Avro: " + keyType);
}

Type guard

boolean hasStringMapKey(LogicalType t) {
    LogicalType k = t instanceof MapType
        ? ((MapType) t).getKeyType()
        : t instanceof MultisetType ? ((MultisetType) t).getElementType() : null;
    return k != null && k.is(LogicalTypeFamily.CHARACTER_STRING);
}

Try / catch

try {
    schema = AvroSchemaConverter.convertToSchema(mapType);
} catch (UnsupportedOperationException e) {
    // convert keys to STRING upstream or use array-of-row representation
    schema = AvroSchemaConverter.convertToSchema(stringKeyedEquivalent);
}

Prevention

When it happens

Trigger: Calling extractValueTypeToAvroMap via convertToSchema with a MapType whose key type is not CHAR/VARCHAR/STRING (e.g. MAP<INT,STRING>), or a MultisetType whose element type is non-string.

Common situations: Flink tables with map columns keyed by integers or timestamps (common in aggregation pipelines like MAP<INT, BIGINT> counts) being written through the Avro format.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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