apache/flink · error · java.lang.UnsupportedOperationException

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

Error message

JSON format doesn't support non-string as key type of map. The type is: {}

What it means

UnsupportedOperationException from createMapConverter when the map key type is not in the CHARACTER_STRING family. JSON object keys are always strings, so a MAP<INT, ...> or MAP<BIGINT, ...> column cannot be populated from JSON and the converter refuses to be created (fail-fast at schema build, before any record is read).

Source

Thrown at flink-formats/flink-json/src/main/java/org/apache/flink/formats/json/JsonParserToRowDataConverters.java:369

                LogicalTypeUtils.toInternalConversionClass(arrayType.getElementType());
        return jp -> {
            if (jp.currentToken() != JsonToken.START_ARRAY) {
                throw new IllegalStateException("Illegal JSON array data...");
            }
            List<Object> result = new ArrayList<>();
            while (jp.nextToken() != JsonToken.END_ARRAY) {
                Object convertField = elementConverter.convert(jp);
                result.add(convertField);
            }
            final Object[] array = (Object[]) Array.newInstance(elementClass, result.size());
            return new GenericArrayData(result.toArray(array));
        };
    }

    private JsonParserToRowDataConverter createMapConverter(
            String typeSummary, LogicalType keyType, LogicalType valueType) {
        if (!keyType.is(LogicalTypeFamily.CHARACTER_STRING)) {
            throw new UnsupportedOperationException(
                    "JSON format doesn't support non-string as key type of map. "
                            + "The type is: "
                            + typeSummary);
        }
        final JsonParserToRowDataConverter keyConverter = createConverter(keyType);
        final JsonParserToRowDataConverter valueConverter = createConverter(valueType);

        return jp -> {
            if (jp.currentToken() != JsonToken.START_OBJECT) {
                throw new IllegalStateException("Illegal JSON map data...");
            }
            Map<Object, Object> result = new HashMap<>();
            while (jp.nextToken() != JsonToken.END_OBJECT) {
                Object key = keyConverter.convert(jp);
                jp.nextToken();
                Object value = valueConverter.convert(jp);
                result.put(key, value);
            }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Change the key type to STRING: MAP<STRING, T> and cast keys downstream (CAST or a UDF) if numeric semantics are needed
  2. Or restructure the data as an ARRAY<ROW<key T, value U>>
  3. For lookups by typed key, normalize keys to strings at the producer

Example fix

-- before
ids MAP<BIGINT, STRING>

-- after
ids MAP<STRING, STRING>
Defensive patterns

Strategy: validation

Validate before calling

if (!mapType.getKeyType().is(LogicalTypeFamily.CHARACTER_STRING)) {
    throw new UnsupportedOperationException("Use MAP<STRING, ...> for JSON");
}

Prevention

When it happens

Trigger: DDL declaring MAP<INT, T> / MAP<BIGINT, T> / MAP<DATE, T> etc. for a JSON table using the parser-based deserializer; also MAP<STRING,...> is fine, MAP with any non-string key type is not.

Common situations: Porting a schema from a format that allows typed keys (Avro maps always have string keys, but Parquet/Row-based tools may suggest typed ones); auto-derived schemas producing numeric keys.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/46ae3b5fdbc9333f. Report an issue: GitHub.