swift-protobuf: Issue parsing unknown enum case

iOS 13.4 Xcode Version 11.4 (11E146) Swift 5 Swift-Protobuf 1.8.0 proto2

My iOS app is using generated code from outdated proto files. Since I’ve compiled the .swift files from the old protos, we’ve added some new cases to one of our enums, and started returning the cases to the client from the backend. I’m getting an error when parsing the JSON data into the Swift Proto objects: unrecognizedEnumValue.

From my understanding of the proto spec, it should be fine to add new enum cases, and clients who don’t have the latest spec map the unknown value to the 0 case. Is there something wrong with how we name our 0th case?

Old Proto

message Product {
    enum State {
        State_INVALID = 0;
        ACTIVE = 1;
        DISCONTINUED = 2;
    }
    optional State state = 1;
}

New Proto

message Product {
    enum State {
        State_INVALID = 0;
        ACTIVE = 1;
        DISCONTINUED = 2;
        FOR_SALE = 3;
        NOT_FOR_SALE = 4;
    }
    optional State state = 1;
}

JSON Being Parsed

{
    "state": "FOR_SALE"
}

Swift JSON Decoding (using Old Proto)

do {
    var options = JSONDecodingOptions()
    options.ignoreUnknownFields = true
    return try Product(jsonUTF8Data: data, options: options)
} catch {
    print(error) // error is printed unrecognizedEnumValue
    return nil
}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 2
  • Comments: 27 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Yup, documentation error.

Edit: Just sent out #977 to fix up the docs.

Looks like protocolbuffers/protobuf#9534 is getting merged soon, as far as a flag for controlling the behavior it will be reusing the unknown field one. Once it’s merged we can look to update.

Hello all! Are there any updates for this issue and #896? I’ve currently encountered this same error and would love to see this merged in.

@srcreigh or @mpdifran – If you could send us a PR with the necessary change, we’d greatly appreciate. The code change looks trivial; just modify the Enum methods in JSONDecoder.swift to ignore Enum decoding errors when options.ignoreUnknownFields is set.

The PR should also include some test cases. You can probably adjust SwiftProtobufTests/Test_JSONDecodingOptions.swift to use something other than Empty as the test message (pretty much any message with valid enum fields) to verify that an unknown enum case in a valid field is ignored when that flag is set.

Test_JSON.swift - testOptionalNestedEnum does test {"optionalNestedEnum":123} <=> .UNRECOGNIZED(123) round tripping for proto3 syntax. So using the option alwaysPrintEnumsAsInts when encoding should give you something that should work (again with proto3 syntax).

If you are in proto2 syntax, I don’t immediately see a test case that would cover an unknown numeric (and stuff it into the unknown fields), but I’d also have to try things on the C++ library to confirm what they do in that case also.

The docs you quote are talking about the binary encoding, not the JSON one. That’s one of the cases where they don’t make a clear distinction between encodings that I mentioned.

As for #896, as the comment suggest, we’re hesitant to add the feature because the main protobuf library doesn’t have it for any other language. If they add then support we’d be willing to added support to the Swift version to match.

From my understanding of the proto spec, it should be fine to add new enum cases, and clients who don’t have the latest spec map the unknown value to the 0 case.

Has this changed recently? Last I checked, this was not in fact the behavior of Google’s protobuf implementations for other languages.

As a rule, we try to stick very closely to the features supported by the main protobuf project in order to avoid confusion and problems for people that are mixing multiple protobuf implementations. Please file an issue with the protocolbuffers/protobuf project and let us know what happens. If you can convince them to adopt this behavior, we’ll happily follow suit.