-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
encoding/protojson: handling google.protobuf.Empty #1620
Comments
#759 (comment) |
Verified, v1.20.0 still reports |
This is the same as #759. Someone responded with protocolbuffers/protobuf#5390 (comment). I'm uncertain if that is affirmative as there has been no further action/decision and the issue was simply closed as inactive. May want to reopen that issue. |
I think this is the other side of #759: I don't know if we should marshal an Empty with a value of {} or no value, but we definitely should parse what other languages are producing. |
The documentation for
Elsewhere, the documentation for
Then, the documentation for
Thus, it seems that the current behavior is correct. That said, the protobuf ecosystem is full of inconsistencies where the implementations do not follow what is documented. Thus, I agree with what @neild says. Pragmatically we should just do whatever the other languages do. |
I’m on the same page as dsnet. Technically, we’re following the spec as written… but that doesn’t much matter if other implementations are accepting this and we’re not. |
I filed protocolbuffers/protobuf#17099 as a first step to get clarity on this. I'm not even sure if we can change the Go behavior if we wanted to because it would be a backwards incompatible change. However, accepting this might be better than the incosistency with C++ and Java and the inability to parse their output. |
Changing behaviour of golang |
I don't see an urgent reason to change Marshal's behavior. However, Unmarshal must be able to parse the output of other languages, even if that output is technically wrong. (I have no opinion on whether it is technically wrong or not.) |
I definitely wasn’t advocating for changing the marshalling output. Only for accepting. |
We still end up with the problem that the output generated by Go cannot be parsed by the other languages. But I agree that extending the unmarshalling makes it more permissive and thus might not be fine (unless someone depends on an error being reported). |
Perhaps I missed it, but the original post only mentioned |
I only tested it with C++, but C++ doesn't accept: It fails with
|
Ah, thanks for looking into that. Given the amount of inconsistency in the ecosytem, I suspect every implementation will need to accept both the case where it is preset with |
#759 is the report for V1's marshaling issue. With the response in protocolbuffers/protobuf#5390 (comment), I think we decided to keep the behavior for V2. I was mistaken in my comment above that this is similar to that marshaling issue. I don't mind having the unmarshaling logic accept what the other languages output. |
I also encountered this issue when using the GCP go SDK (I wonder if this is the most common scenario?). Google LROs use anypb.Any for the result field, and there are multiple APIs service which do not send the value field when the result is emptypb.Empty, triggering this problem. One mitigating factor with the GCP go SDK is that it only applies to protojson, and the GCP go SDK seems to default to true proto encoding now for most services. However for protojson, the GCP Go SDK does pass both AllowPartial and DiscardUnknown. I would think that AllowPartial=true should mean that a missing I don't know if we should also pass down DiscardUnknown. I would think yes, from the perspective of obeying the user's intent (and then maybe we should pass down all the options?). But also because I think DiscardUnknown is important - we presumably do not want to fail when the service adds new fields. Because this doesn't happen all the time, I'm guessing that this is only relevant for a new field in anypb.Any, so maybe this isn't very likely, but it still seems like good future-proofing. The CL is https://go-review.git.corp.google.com/c/protobuf/+/617516 |
My primary concern here would be that if the The problem here is wholly only with wrapping the emptypb.Empty type, and we should probably be allowing this missing |
Yes - AllowPartial might require clients to do extra validation. But this change is adding/fixing support for AllowPartial, i.e. if the user passes AllowPartial, then we honor that. There is also an issue today (I would argue) that we don't honor the user's AllowPartial instruction for this case. (Aside: is AllowPartial actually a bad idea in the context of proto now recommending all fields be optional? e.g. I don't think structpb.Value has any required fields, though I am by no means the proto expert!)
Now that you mention it, I do agree as the value field is not marked as required AFAICT: https://github.com/protocolbuffers/protobuf/blob/64e14b42c4255c5e2759f795ee4bcf1d17b00ae5/src/google/protobuf/any.proto#L161 If we think this change is safe, happy to submit a CL for this or test a CL if that is useful. (My personal interest here is in being able to handle these "missing value" LROs in the Google Cloud go SDK, beyond that I'm amenable to whatever approach you think is best) |
We don’t honor it for good reason, it’s a well-known type, and thus has a canonical representation in JSON:
The problem is that arguably not emitting the But since other of the Big4 generators are marshalling and unmarshalling it, even when PS:
This has nothing to do with anything, because it’s covered under the WKTs explicitly on the JSON mapping standard linked to above. It’s required, because the standard for |
I don't think We should change the Go JSON parser to accept Every parser that doesn't accept The protobuf project maintainers should decide which form is the correct one, and we should eventually change all encoders to produce it. Although that's going to be tricky to do without breaking anything, so we'd probably want to wait some period of time after aligning parsers to handle either form. We should not change |
Fair enough :-)
I'll send a version that does this. Edit: https://go-review.googlesource.com/c/protobuf/+/618395 |
https://go.dev/cl/618395 changes the Go JSON unmarshaler to accept the output produced by C++/Java, but C++ (and I think Java) still don't accept the output produced by Go. Fully fixing this issue requires addressing that. Just changing the Go marshaler isn't going to work, since we'd start producing output that can't be parsed by earlier versions of protojson. Addressing the issue will require coordinating with the C++/Java maintainers (at least). Perhaps that should be a new issue, but I'm going to reopen this one for now so we don't lose track of it. |
This edge case should also be added the conformance test suite to ensure that future implementations agree with each other. |
@justinsb thank you so much for the fix. |
@orloffv sorry for the slow reply. We plan to do a release in 1-2 weeks. If you need the fix sooner, i think it's fine to just update directly to fb995f1 for the time being (e.g. |
@chressie |
@orloffv we just cut a new release https://github.com/protocolbuffers/protobuf-go/releases/tag/v1.35.2, which includes the change. |
Version:
v1.34.1
Hi, I've encountered interop problems with protojson encoding between different languages
The following code produces error in golang:
Output:
Yet, this snippet in Java:
produces output:
python, same thing:
Output:
It doesn't seem golang implementation should expect
value
fieldThe text was updated successfully, but these errors were encountered: