When logging some protobuf messages in an application, I noticed that zero value enums were not being printed out. I added a couple of test cases to a branch on my fork to illustrate this:
And the output is as follows:

In the documentation (https://developers.google.com/protocol-buffers/docs/proto3#enum), the zero value is a valid, default value:
As you can see, the Corpus enum's first constant maps to zero: every enum definition must contain a constant that maps to zero as its first element. This is because:
- There must be a zero value, so that we can use 0 as a numeric default value.
One thing to note that may be an issue is that in the proto2 implementation, enum fields are pointers (thus allowing a check for nil when determining the value to print), whereas in the proto3 implementation, they are not.
Proto2 Example: https://github.com/mcos/protobuf/blob/709153eb2043a28b5e4a18f36543312a2f7dc302/proto/testdata/test.pb.go#L1384
Proto3 Example: https://github.com/mcos/protobuf/blob/709153eb2043a28b5e4a18f36543312a2f7dc302/proto/proto3_proto/proto3.pb.go#L66
Is this a regression or an explicit design choice?
The only way to get around this right now is to use the zero value as some throwaway or discardable value (for example, using _). This has certain limitations too, in that the zero value could be a valid value (given the documentation); also per the protobuf scoping rules, we cannot duplicate that throwaway zero value across messages in the same package, causing compliation issues.
In proto3, zero value fields are indistinguishable from unset fields, by design. They are not sent on the wire either.
I understand that is the case, however I think the issue raised shows a different problem in that the fmt.Stringer interface-satisfying .String() method is not called for zero value enum fields. A zero-value is a valid value for the field and should be treated as such when invoking that interface method.
This is working as intended. proto3 zero-values are omitted in the JSON format too.
The zero-value should be a "throwaway" value: it's also what you will see if the sender of a serialized message sets the field to an invalid or unrecognized value.
This makes it difficult to generate JSON that represents items where zero is a valid value. For example, 0 is a valid value for temperature in Celsius or a bank account balance.
How to solve this problem?
For cases where zero is a valid value, then if the value is missing in the JSON, then it is zero.
Beyond this neigh-tautological comment, which should rightfully be met with “duh”, the bug was closed as Invalid, because this is a matter of the proto specification itself.
This codebase is specifically for the Golang implementation of that specification. It has neither the scope nor authority to assert a unilateral change to the protobuf specifications.
Can you please just tell, why this happens?
It has been extensively explained above: zero values are omitted.
From https://developers.google.com/protocol-buffers/docs/proto3#default
Also note that if a scalar message field is set to its default, the value will not be serialized on the wire.
Most helpful comment
This makes it difficult to generate JSON that represents items where zero is a valid value. For example, 0 is a valid value for temperature in Celsius or a bank account balance.