Unknown enum values in repeated fields cause deserialization crash
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 4.4k
- Forks
- 627
- Avg merge
- 3d 15m
- Merged PRs (30d)
- 20
Description
Problem Summary
When deserializing JSON containing a repeated enum field (List<SomeEnum>) with unknown enum values, Wire's GSON integration crashes with IllegalArgumentException: field_name.contains(null) because:
EnumJsonFormatter.fromString()returnsnullfor unknown enum valuesListJsonAdapteradds thesenullvalues to the result list- Wire's
immutableCopyOf()rejects lists containingnull
Affected Code Paths
1. EnumJsonFormatter.kt (wire-runtime)
override fun fromString(value: String): E? {
return stringToValue[value]
// If the constant is unknown to our runtime, we return a `Unrecognized` instance if it has
// been generated.
?: unrecognizedClassConstructor?.newInstance(value.toInt())
}
When there's no Unrecognized class (standard enum generation), this returns null for unknown values.
2. GsonJsonIntegration.kt (wire-gson-support)
private class ListJsonAdapter<T>(
private val single: TypeAdapter<T>,
) : TypeAdapter<List<T?>>() {
override fun read(reader: JsonReader): List<T?> {
val result = mutableListOf<T?>()
reader.beginArray()
while (reader.hasNext()) {
result.add(single.read(reader)) // Adds null from EnumJsonFormatter
}
reader.endArray()
return result // List contains nulls!
}
}
3. Internal.kt (wire-runtime)
fun <T> immutableCopyOf(name: String, list: List<T>): List<T> {
if (list.contains(null)) {
throw IllegalArgumentException("$name.contains(null)") // CRASH!
}
// ...
}
Reproduction
Given this proto:
enum HotelPageBlock {
UNKNOWN = 0;
MAP_BLOCK = 1;
BENEFITS_BLOCK = 2;
}
message RubiricHotelPageBlockOrder {
repeated HotelPageBlock hotel_page_blocks = 1;
}
And this JSON with an unknown enum value (e.g., server added NEW_BLOCK = 17):
{
"hotelPageBlocks": ["MAP_BLOCK", "NEW_BLOCK", "BENEFITS_BLOCK"]
}
Deserialization crashes:
java.lang.IllegalArgumentException: hotel_page_blocks.contains(null)
at com.squareup.wire.internal.Internal__InternalKt.immutableCopyOf(Internal.kt:72)
at proto.hotels.v1.RubiricHotelPageBlockOrder.<init>(RubiricHotelPageBlockOrder.kt:48)
Expected Behavior
Wire should handle unknown enum values in repeated fields gracefully, either by:
- Filtering out unknown values (like proto binary decoding does - stores in
unknownFields) - Using the default enum value (first constant, typically
UNKNOWN = 0) - Providing a configuration option to choose the behavior
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with EnumJsonFormatter.kt, GsonJsonIntegration.kt, and Internal.kt, then reproduce the repeated-enum JSON failure described in the issue. Resolve which unknown-value behavior is intended—filtering, defaulting, or configuration—and verify that deserialization no longer crashes for the supplied example.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100