Card 05/ 09
Protocol Buffers and Field Numbers
A protobuf message is encoded by field number, so numbers can never be reused and names can change freely.
Protocol Buffers, or protobuf, encodes each field of a message with its number and value, not its name. A reader decodes field 2 as whatever its own .proto file says field 2 is. That makes the numbers the real contract: a name can change without breaking a binary client, while changing or reusing a number makes old and new code read each other's data wrongly, without any error.
Reservedsafe
customer_name = 2 is deleted, and the message gains reserved 2; and reserved "customer_name";. The compiler now refuses any new field with that number or name. Old clients that still send field 2 have it ignored by new servers.
Number reusedsilently wrong
customer_name = 2 is deleted, and a new int64 discount_pence = 2; is added. An old client sends a name as field 2, and the new server tries to read it as a discount. The data is corrupted or the decode fails, and nothing in the build warned anyone.
Safe changes. Add a field with a new number; old readers skip numbers they do not know, which makes protobuf readers tolerant by default. Remove a field and reserve its number and name. Rename a field, for the binary format.
Breaking changes. Change a field's number, reuse a number, or change a field's type to one that is not compatible on the wire.
One caveat on renaming. Protobuf also has a JSON form, used by gRPC gateways and some logs, and JSON uses field names. A rename that is safe in binary breaks a client reading the JSON form.
Numbers are cheap at the start. Fields 1 to 15 take one byte to tag on the wire, so give them to the fields sent most often.
So treat field numbers as permanent, reserve every number you remove, and never reuse one.
← → move through sections and cards