Avro¶
Status: Native for both decode and encode. A short list of row-type and option gaps falls back to Flink's own Avro (de)serializer, listed below.
This page covers the bare avro format — schema supplied inline via the format's own options, no
schema registry. For the Confluent Schema Registry-framed variant, see
Avro Confluent. For changelog envelopes (Debezium/OGG/Maxwell/Canal JSON), see
CDC JSON.
Decode¶
Avro decode runs on the shallow native decode operator and on the native Kafka source's split reader, over the same row type Flink's own Avro factory accepts. The split reader routes decode through the JVM only when a format needs per-batch JVM work — as the registry lookup does for Avro Confluent.
Parity behaviors, pinned against Flink's converter by AvroDecodeParityTest:
- Every avro timestamp long decodes as epoch millis regardless of the schema's declared unit —
Flink's converter has no micros path, so a
timestamp-microsschema resolves through the same millis read in both engines. - TINYINT/SMALLINT narrow with Java's wrapping
byteValue()/shortValue(). - A decimal whose digits exceed the declared precision decodes to NULL.
- A null Kafka value (a tombstone) is dropped silently.
avro.timestamp_mapping.legacy is honored in both directions: the corrected (false) mapping
derives local-timestamp-millis/micros for TIMESTAMP and unlocks TIMESTAMP_LTZ up to precision 6
natively — but only at the top level. Flink itself rejects a nested TIMESTAMP_LTZ under the
corrected mapping (its converter factory drops the flag for nested rows, and its schema derivation
drops it inside collections), so those shapes fall back to reproduce Flink's own submission
failure.
Decode fallback conditions¶
| Condition | Why |
|---|---|
| A row type Flink's own Avro factory rejects at job submission (RAW and other unmapped types, TIMESTAMP_LTZ under the legacy mapping, TIMESTAMP/TIME precision beyond the mapping's limit, a non-string map key) | Declined at plan time — the provider runs the same schema/converter derivation Flink's factory runs, so the fallback reproduces Flink's exact submission failure instead of a native-planner abort. |
TIME(0) column |
Flink keeps an avro time-millis value's full milliseconds in a TIME(0) column, while the Arrow boundary's second-precision form would truncate them. TIME(1..3) is native and exact — but SQL DDL resolves every TIME(p) column to TIME(0) in the catalog, so a TIME column in a SQL-defined table always stays on Flink; TIME(1..3) is reachable only through Table-API-defined schemas. |
BINARY(n) column |
Flink accepts avro bytes of any length into a BINARY(n) column, which the boundary's fixed-size form can't hold. (VARBINARY is native; BINARY(n) encodes fine — see below.) |
avro.encoding = 'json' |
Avro's JSON encoding is a different wire format the native decode doesn't read. |
A nested TIMESTAMP_LTZ column under avro.timestamp_mapping.legacy = false |
Flink's own converter factory and schema derivation both reject this shape; the native gate mirrors the submission failure. |
Encode¶
The writer schema is derived from the sink row type with Flink's own converter and shipped to the native encoder verbatim, so record names, null-first unions, and logical types match Flink's bytes exactly.
Two Flink converter behaviors are reproduced deliberately, not "fixed":
- Every timestamp flavor is written as an epoch-millisecond long even into a
*-timestamp-microsschema (Flink callstoEpochMilliunconditionally, so micros values read 1000x small and sub-millisecond digits are dropped). - Map/multiset entries serialize in
java.util.HashMapiteration order (Flink copies each map through a HashMap before Avro walks itsentrySet), including first-position/last-value duplicate-key collapse. A NULL map key fails the record at runtime, as Flink's converter does — a data-dependent failure that can't gate at plan time.
avro.timestamp_mapping.legacy is honored both ways (contrast
Avro Confluent, which hard-wires it).
BINARY(n) columns, which decode declines (above), encode fine: the schema says bytes and the
fixed-size boundary value widens losslessly.
One loud native-only failure mode: nine map keys sharing one hash bucket of a 64-slot-or-larger table would make Java treeify the bin and iterate in red-black-tree order, which the native encode does not reproduce — it fails the record with an explicit error instead of silently reordering.
Both avro and avro-confluent are legal upsert-kafka key and value formats (Avro is
insert-only), with the key format serializing the primary-key projection as its own format
instance.
Encode fallback conditions¶
| Condition | Why |
|---|---|
| A row type the writer-schema derivation rejects (RAW, intervals, TIME(p) with p>3, TIMESTAMP beyond the active mapping's precision, TIMESTAMP_LTZ under the legacy mapping, a non-string map key) | Declined at plan time; Flink raises its own submission error. |
TIME(0) column |
Same second-vs-millisecond precision gap as decode. |
| A NULL map key | Fails the record at runtime, matching Flink's converter — a data-dependent failure that can't gate at plan time. |
Missing streamfusion-avro JAR |
The provider seam treats a missing optional format module as an absent native format, not a linkage failure. |