Protocol Buffers Pitfall: Adding Enum Values

One of Protocol Buffers (aka protobuf) strengths is its backward and forward compatibility: following some common sense, old protobuf messages types can be read into newer versions of itself, and vice versa. With enums, however, you better be careful. They can break your logic in a surprising way.

Consider you publish an Android app version 1 using this protobuf enum to talk to the cloud:

enum Animal {
    MOUSE = 1;
    CAT = 2;
}

After some time, you add another animal to version 2:

enum Animal {
    MOUSE = 1;
    CAT = 2;
    ELEPHANT = 3;
}

However, version 1 of the app is still out there because you don’t want to force users to update. So guess what the old app version gets when it receives an elephant from a version 2 data source? A mouse!

I don’t know about you, but that took me by surprise. I would have expected a null value, because the elephant is unknown to the old version. After some digging in the generated protobuf code, it became clear that Protocol Buffers uses the first value as the default value.

Fixing Protobuf Enums

So, how to make protobuf enums future proof? Best practices are to introduce a special enum value. By placing it in the first position, which is also the default value.

enum Animal {
    UNKNOWN = 0;
    MOUSE = 1;
    CAT = 2;
    ELEPHANT = 3;
}

This version is safe when a kangaroo hops in with the next version. The kangaroo will result in a UNKNOWN value, and can be thus identified accordingly by the app.

Additional Notes for Java

For Java developers, protobuf imposes some annoying naming constraints on emun values. If you have multiple enums in the same file, you will get an error like this when you want to define “UNKNOWN” values for more than one enum:

Note that enum values use C++ scoping rules, meaning that enum values are siblings of their type, not children of it.  Therefore, “UNKOWN” must be unique within the global scope, not just within “Animal”.

Well, alright, let’s make it “UNKNOWN_ANIMAL” and protobuf is happy.

Protobuf 3 Enums

Protocol Buffers 3 will make deep changes. One of them might resolve the enum issue according the release notes of Protocol Buffers v3.0.0-alpha-1:

4. Fix semantics for unknown enum values.

Sounds promising, but Protobuf 3 a story for another day. Today is the day to double check your protobuf enums.

Elephant image credit: Marc Slingerland via freeimages.com

3 thoughts on “Protocol Buffers Pitfall: Adding Enum Values”

  1. Thank you so much! This has probably saved me many hours of trial and error and figuring out what exactly is going wrong.

    1. Thx for this post, was looking for quick confirmation of default “default value” for enum (without default specified) :).

      BTW, IMO this is correct behaviour, and in my case first value was already kind-of-default, null is never good 🙂

  2. Interesting behavior. I’ve already put an “Unknown” enum value in my implementations but I have put them at the very end of the expected range. So if I have 5 enums, then I put UNKNOWN = 100; just to be sure. Could I move UNKNOWN = 100; to the top of the enum list or would I also have to change the 100 to -1 or something?

    Thank you for your article!

Leave a Reply

Your email address will not be published. Required fields are marked *