zig-protobuf icon indicating copy to clipboard operation
zig-protobuf copied to clipboard

Incorrect JSON serialization for otel protos

Open jaronoff97 opened this issue 3 weeks ago • 4 comments

Hello! big fan of the library, however, I'm running into an issue with json serialization.

        const resource_attributes = [_]KeyValue{
            .{ .key = "service.name", .value = .{ .value = .{ .string_value = self.service.name } } },
            .{ .key = "service.instance.id", .value = .{ .value = .{ .string_value = self.service.instance_id } } },
            .{ .key = "service.version", .value = .{ .value = .{ .string_value = self.service.version } } },
            .{ .key = "service.namespace", .value = .{ .value = .{ .string_value = self.service.namespace } } },
        };

Is correct and matches the other proto syntax one may see in something like golang. I did find, however, that when encoding to JSON, the extra value field is included which causes an error when reading a proto message in other languages:

[
  {
    "key": "service.name",
    "value": {
      "value": {
        "stringValue": "example"
      }
    }
  },
  {
    "key": "service.instance.id",
    "value": {
      "value": {
        "stringValue": "example-1764783202368-14467194"
      }
    }
  },
  {
    "key": "service.version",
    "value": {
      "value": {
        "stringValue": "latest"
      }
    }
  },
  {
    "key": "service.namespace",
    "value": {
      "value": {
        "stringValue": "example"
      }
    }
  }
]

as opposed to the expected like this JSON example elsewhere in otel.

I am encoding like so:

const request_body = try request.jsonEncode(.{}, self.allocator);
        defer self.allocator.free(request_body);

Let me know if there's something I'm doing incorrect here, but I believe this is a bug in the json serialization.

jaronoff97 avatar Dec 03 '25 17:12 jaronoff97

Hi @jaronoff97, it seems that the generated json is somehow valid, assuming we are looking at the same .proto

// Represents any type of attribute value. AnyValue may contain a
// primitive value such as a string or integer or it may contain an arbitrary nested
// object containing arrays, key-value lists and primitives.
message AnyValue {
  // The value is one of the listed fields. It is valid for all values to be unspecified
  // in which case this AnyValue is considered to be "empty".
  oneof value {
    string string_value = 1;
    bool bool_value = 2;
    int64 int_value = 3;
    double double_value = 4;
    ArrayValue array_value = 5;
    KeyValueList kvlist_value = 6;
    bytes bytes_value = 7;
  }
}

I'm not against shadowing one level of a message serialization just to skip the oneof value. But we all need agreement and prior art references to prevent local minimums, is this behavior documented in Go and other languages? Is it opt-in?

menduz avatar Dec 03 '25 18:12 menduz

@menduz it seems most implementation infer it from this issue. The behavior isn't well documented (per that comment), but going through other issues it's clear this is the expected behavior

jaronoff97 avatar Dec 03 '25 20:12 jaronoff97

I took a look at the default behavior of protobuf cpp and it seems consistent with this proposal. They do have one caveat for serialization, it may become handy now that you are looking at the serialization.

message TestOneof {
  // In JSON format oneof fields behave mostly the same as optional
  // fields except that:
  //   1. Oneof fields have field presence information and will be
  //      printed if it's set no matter whether it's the default value.
  //   2. Multiple oneof fields in the same oneof cannot appear at the
  //      same time in the input.
  oneof oneof_value {
    int32 oneof_int32_value = 1;
    string oneof_string_value = 2;
    bytes oneof_bytes_value = 3;
    EnumType oneof_enum_value = 4;
    MessageType oneof_message_value = 5;
    google.protobuf.NullValue oneof_null_value = 6;
  }
}

https://github.com/protocolbuffers/protobuf/blob/f66ad439e1ddab24f588da3df00daa7bbba3142c/src/google/protobuf/util/json_format_proto3.proto#L75-L90

menduz avatar Dec 04 '25 13:12 menduz

Hello @jaronoff97 , thanks a lot for this issue and the PR you started. As said in the readme, json encoding/decoding is still a beta feature in this library, so i'm not surprised we fall in some problems. Thanks a lot for helping us improving the library.

Arwalk avatar Dec 05 '25 06:12 Arwalk