apache/flink · error · IllegalArgumentException

The Avro schema is not a nullable type: %s

Error message

The Avro schema is not a nullable type: %s

What it means

The nullable wrapper in RowDataToAvroConverters accepts only two-element unions of the exact shapes [T, null] or [null, T]. A UNION schema with 3+ branches (or 2 branches where neither is null) throws IllegalArgumentException('The Avro schema is not a nullable type: %s') with the full schema printed.

Source

Thrown at flink-formats/flink-avro/src/main/java/org/apache/flink/formats/avro/RowDataToAvroConverters.java:248

            private static final long serialVersionUID = 1L;

            @Override
            public Object convert(Schema schema, Object object) {
                if (object == null) {
                    return null;
                }

                // get actual schema if it is a nullable schema
                Schema actualSchema;
                if (schema.getType() == Schema.Type.UNION) {
                    List<Schema> types = schema.getTypes();
                    int size = types.size();
                    if (size == 2 && types.get(1).getType() == Schema.Type.NULL) {
                        actualSchema = types.get(0);
                    } else if (size == 2 && types.get(0).getType() == Schema.Type.NULL) {
                        actualSchema = types.get(1);
                    } else {
                        throw new IllegalArgumentException(
                                "The Avro schema is not a nullable type: " + schema.toString());
                    }
                } else {
                    actualSchema = schema;
                }
                return converter.convert(actualSchema, object);
            }
        };
    }

    private static RowDataToAvroConverter createRowConverter(
            RowType rowType, boolean legacyTimestampMapping) {
        final RowDataToAvroConverter[] fieldConverters =
                rowType.getChildren().stream()
                        .map(legacyType -> createConverter(legacyType, legacyTimestampMapping))
                        .toArray(RowDataToAvroConverter[]::new);
        final LogicalType[] fieldTypes =
                rowType.getFields().stream()

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Reduce the union to exactly ["null", T] or [T, "null"].
  2. If multiple types are genuinely needed, wrap them in a record or pick one concrete type and convert data upstream.
  3. If the column is actually non-nullable, remove the union so a plain schema reaches the converter.

Example fix

// before
{"name":"v","type":["string","int","null"]}

// after
{"name":"v","type":["null","string"]}
Defensive patterns

Strategy: validation

Validate before calling

static void validateNullableUnion(Schema s) {
    if (s.getType() == Schema.Type.UNION) {
        List<Schema> ts = s.getTypes();
        boolean ok = ts.size() == 2
                && (ts.get(0).getType() == Schema.Type.NULL || ts.get(1).getType() == Schema.Type.NULL);
        if (!ok) throw new IllegalArgumentException("Not a simple nullable union: " + s);
    }
}

Type guard

static boolean isSimpleNullableUnion(Schema s) {
    if (s.getType() != Schema.Type.UNION) return false;
    List<Schema> ts = s.getTypes();
    return ts.size() == 2 && ts.stream().anyMatch(t -> t.getType() == Schema.Type.NULL);
}

Prevention

When it happens

Trigger: A field converter receives a schema whose type is UNION but is not a simple nullable union — e.g. ["string","int","null"] or ["string","int"] — while the RowType marks the field nullable.

Common situations: Hand-crafted or Avro-IDL-generated schemas with multi-alternative unions; schema evolution adding an alternative to a previously nullable field.

Related errors


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