apache/flink · error · JsonParseException
Unable to serialize VARIANT value.
Error message
Unable to serialize VARIANT value.
What it means
Thrown by RowDataToJsonConverters.convertVariant when ObjectMapper.readTree fails to re-parse the JSON text produced by Variant.toJson() for a VARIANT value being written to JSON. The variant's textual form should be valid JSON, so an IOException here means the variant object could not render parseable JSON — typically a malformed or corrupted BinaryVariant instance.
Source
Thrown at flink-formats/flink-json/src/main/java/org/apache/flink/formats/json/RowDataToJsonConverters.java:177
}
}
private RowDataToJsonConverter createDecimalConverter() {
return (mapper, reuse, value) -> {
BigDecimal bd = ((DecimalData) value).toBigDecimal();
return mapper.getNodeFactory()
.numberNode(
mapper.isEnabled(WRITE_BIGDECIMAL_AS_PLAIN)
? bd
: bd.stripTrailingZeros());
};
}
private JsonNode convertVariant(ObjectMapper mapper, JsonNode reuse, Object value) {
try {
return mapper.readTree(((Variant) value).toJson());
} catch (IOException e) {
throw new JsonParseException("Unable to serialize VARIANT value.", e);
}
}
private RowDataToJsonConverter createDateConverter() {
return (mapper, reuse, value) -> {
int days = (int) value;
LocalDate date = LocalDate.ofEpochDay(days);
return mapper.getNodeFactory().textNode(ISO_LOCAL_DATE.format(date));
};
}
private RowDataToJsonConverter createTimeConverter() {
return (mapper, reuse, value) -> {
int millisecond = (int) value;
LocalTime time = LocalTime.ofNanoOfDay(millisecond * 1000_000L);
return mapper.getNodeFactory().textNode(SQL_TIME_FORMAT.format(time));
};
}View on GitHub (pinned to 2f3c205e92)
Solutions
- Verify the VARIANT value is produced by the same Flink version's VARIANT tooling (BinaryVariantInternalBuilder) rather than raw bytes
- Re-derive the variant from its original JSON instead of restoring/passing opaque binary variants across versions
- If writing the raw variant is the goal, serialize the column as the variant's JSON text (STRING) via toJson() in a UDF and write that
- Check for version mismatches between the producing job/format and the consuming JSON sink, and align them
Example fix
// before: variant built from opaque bytes byte[] raw = ...; BinaryVariant v = BinaryVariant.fromBytes(raw); // after: build from JSON so toJson() is guaranteed parseable BinaryVariant v = BinaryVariantInternalBuilder.parseJson(jsonText, false);
Defensive patterns
Strategy: validation
Validate before calling
String json = ((Variant) value).toJson();
try { mapper.readTree(json); } catch (IOException e) { /* do not write this variant to JSON sink; quarantine */ } Try / catch
catch (JsonParseException e) for 'Unable to serialize VARIANT' — treat as data corruption; drop or quarantine the record, never a silent fallback.
Prevention
- Build variants only via BinaryVariantInternalBuilder
- Do not restore opaque variant bytes across Flink versions
- Unit-test variant round-trips (toJson/readTree) on representative data
When it happens
Trigger: Serializing a RowData with a VARIANT column through the 'json' format where the Variant value is malformed (constructed from corrupted bytes, an incompatible binary layout, or an invalid internal build), causing Variant.toJson() to emit something readTree rejects.
Common situations: VARIANT data produced by a different Flink/table version with a changed binary layout; hand-constructed BinaryVariant from raw bytes; corrupted state after a checkpoint restore across versions; bugs in variant-building code paths.
Related errors
- Invalid version %d
- Unrecognized version or corrupt state: {version}
- unrecognized compatibility type.
- Unrecognized version: {}
- Unrecognized version: {}
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/c6302f57a8754998.
Report an issue: GitHub.