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
- Reduce the union to exactly ["null", T] or [T, "null"].
- If multiple types are genuinely needed, wrap them in a record or pick one concrete type and convert data upstream.
- 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
- Ban multi-branch unions in Avro schemas used with Flink RowData serialization.
- Add a schema lint step to CI that rejects unions other than [null,T].
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
- Avro Union with NULL type is only supported. Unsupported typ
- Schema must be set when using Generic Record
- Unsupported Avro type '%s'.
- Field types must not be null.
- Missing type for included field {}.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/ddcc1d46bcd7e329.
Report an issue: GitHub.