Avro 129 decodes with two schemas, the writer's schema that produced the bytes and the reader's schema the application wants, and schema resolution matches fields by name. This script reads version 1 data with an evolved version 2 and a broken version 3:
import copy, io, json
from fastavro import parse_schema as parse, schemaless_reader, schemaless_writer
from orders_io import orders
v1 = json.load(open("order.avsc"))
buf = io.BytesIO()
schemaless_writer(buf, parse(v1), next(orders())) # data written with version 1
v2 = copy.deepcopy(v1) # the reader's evolved schema
f = {x["name"]: x for x in v2["fields"]}
f["customer_id"]["type"] = "long" # promote int -> long
f["channel"].update(name="sales_channel", aliases=["channel"]) # rename via an alias
v2["fields"].remove(f["currency"]) # dropped: value skipped
v2["fields"].append({"name": "gift_wrap", "type": "boolean", "default": False})
v3 = copy.deepcopy(v2)
v3["fields"].append({"name": "gift_note", "type": "string"}) # added without a default
for name, reader in (("v2", v2), ("v3", v3)):
buf.seek(0)
try:
rec = schemaless_reader(buf, parse(v1), parse(reader))
print(name, {k: rec[k] for k in ("customer_id", "sales_channel", "gift_wrap")})
except Exception as e:
print(name, f"{type(e).__name__}: {e}")Output
v2 {'customer_id': 2518, 'sales_channel': 'ios', 'gift_wrap': False}
v3 SchemaResolutionError: No default value for field gift_note in com.example.booknest.Order| Change | Resolution rule |
|---|---|
| Reader adds a field | Allowed only with a default, used for old data |
| Reader drops a field | Allowed: the writer's value is skipped |
| Rename | Reader lists the old name in aliases |
| Widen a type | int to long, float, double; long to float, double; float to double |
| Text and binary | string and bytes are interchangeable |
| New enum symbol | Old readers fail unless their enum declares a default symbol |
Registries enforce these rules as modes: backward (new readers read old data, as version 2 does), forward (old readers read new data) and full (both). Adding or removing fields with defaults keeps full compatibility. Schema Evolution compares the modes across formats; Apache Kafka and Managed Cloud Kafka lets a registry reject a bad schema before any producer uses it.