40

One of the attractive features of protocol buffers is that it allows you extend the message definitions without breaking code that uses the older definition. In the case of an enum according to the documentation:

a field with an enum type can only have one of a specified set of constants as its value (if you try to provide a different value, the parser will treat it like an unknown field)

therefore if you extend the enum and use the new value then a field with that type in old code will be undefined or have its default value, if there is one.

What is a good strategy to deal with this, knowing that in future the enum may have additional values added?

One way that comes to mind is to define an "undefined" member of the enum and make that the default, then old code will know it has been sent something that it can't interpret. Is that sensible, are there better ways to deal with this situation?

glennr
  • 2,069
  • 2
  • 26
  • 37
  • A further solution is to never add values to an existing enum, but instead add a new one. – glennr May 03 '12 at 20:44
  • 2
    From the code I've been staring at today (Java), it's not clear that a default value helps. The enum field already has a default value (the first value of the enum), but that value is assigned and unset. Thus, the isInitialized() fails, because the scan of the required fields sees that the hasField boolean is false. Enum, required, extendable - pick any two? – VoiceOfUnreason Aug 17 '12 at 19:55
  • @VoiceOfUnreason: Correct: if you make the enum required, unexpected values will be seen as incompatible. Having a default only helps if it's optional. – poolie Jun 19 '13 at 06:27

2 Answers2

33

Yes, the best approach is to make the first value in the enum something like UNKNOWN = 0. Then old programs reading a protobuf with an enum value they don't recognize will see it as UNKNOWN and hopefully they can handle that reasonably, eg by skipping that element.

If you want to do this you'll also want to make the enum be optional not required.

required, generally, means "I'd rather the program just abort than handle something it doesn't understand."

Note that it must be the first value declared in the proto source - just being the zero value doesn't make it the default.

poolie
  • 9,289
  • 1
  • 47
  • 74
  • 3
    I tested with Protocol Buffer Version 3 and if a client tries to unmarshal an enum that has a new value (not yet present in the client proto), it doesn't map to the first value (UNKNOWN=0 in the example), it simply throws an exception. This behaviour caused me to use String instead of enum, because it would create a coupling between the client and server. – Toyo Sep 29 '20 at 21:41
  • @Toyo Can you provide a sample code where you see this behaviour? – Himanshu Tanwar Sep 13 '22 at 15:09