Title: Having trouble with deserialising JSON nullable fields in Kotlin with custom decoder
Tags: kotlin;serialization
Question: I am having difficulty decoding this JSON with Kotlin Serialization. It works well when the data field is not empty. However when the data field is null and the errors field is present I get this runtime exception:
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 7: Expected start of the object '{', but had ':' instead
JSON input: {&quot;data&quot;:null,&quot;errors&quot;:[{&quot;path&quot;:null,&quot;locations&quot;:[{&quot;line&quot;:3,&quot;column&quot;:5,&quot;sourceName&quot;:null}],&quot;message&quot;:&quot;Validation error of type FieldUndefined: Field 'mee' in type 'Query' is undefined @ 'mee'&quot;}]})
The JSON pretty printed:
&quot;data&quot;: null,
&quot;errors&quot;: [{
&quot;path&quot;: null,
&quot;locations&quot;: [{
&quot;line&quot;: 3,
&quot;column&quot;: 5,
&quot;sourceName&quot;: null
}],
&quot;message&quot;: &quot;Validation error of type FieldUndefined: Field 'mee' in type 'Query' is undefined @ 'mee'&quot;
}]
The code which is mostly stolen from How to serialize a generic class with kontlinx.serialization? :
class ApiResponse<T&gt;(
@SerialName(&quot;data&quot;)
val data: T? = null,
@SerialName(&quot;errors&quot;)
val errors: List<ErrorResponse&gt;? = null
@Serializable
class ErrorResponse(
val path: String? = null,
val locations: List<Location&gt;? = null,
val errorType: String? = null,
val message: String? = null
@Serializable
data class Location(
val line: Int? = 0,
val column: Int? = 0,
val sourceName: String? = null
@ExperimentalSerializationApi
class ApiResponseSerializer<T&gt;(private val dataSerializer: KSerializer<T&gt;) : KSerializer<ApiResponse<T&gt;&gt; {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(&quot;ApiResponseDataSerializer&quot;) {
val dataDescriptor = dataSerializer.descriptor
element(&quot;data&quot;, dataDescriptor)
element(&quot;errors&quot;, ErrorResponse.serializer().descriptor)
override fun deserialize(decoder: Decoder): ApiResponse<T&gt; =
decoder.decodeStructure(descriptor) {
var data: T? = null
var errors: List<ErrorResponse&gt;? = null
val listSerializer = ListSerializer(ErrorResponse.serializer())
loop@ while (true) {
when (val i = decodeElementIndex(descriptor)) {
0 -&gt; data = decodeSerializableElement(descriptor, i, dataSerializer, null)
1 -&gt; errors = decodeSerializableElement(descriptor, i, ListSerializer(ErrorResponse.serializer()), null)
CompositeDecoder.DECODE_DONE -&gt; break
else -&gt; throw SerializationException(&quot;Unknown index $i&quot;)
}
}
ApiResponse(data, errors)
}
override fun serialize(encoder: Encoder, value: ApiResponse<T&gt;) {
encoder.encodeStructure(descriptor) {
val listSerializer = ListSerializer(ErrorResponse.serializer())
encodeNullableSerializableElement(descriptor, 0, dataSerializer, value.data)
value.errors?.let {
encodeNullableSerializableElement(descriptor, 1, listSerializer, it)
}
}
I tried using decodeNullableSerializableElement, but I got a compilation error. I couldn't find a way to fix that.
Type mismatch: inferred type is KSerializer<T&gt; but DeserializationStrategy<TypeVariable(T)?&gt; was expected
Any help would be appreciated, I am very new to Android and Kotlin.

Here is the accepted answer: Always pays to come back after a good nights sleep. Not sure why I had so much trouble with decodeNullableSerializableElement yesterday, but today I played around and got it working.
Made 3 changes
Made T optional in class parameter
Added .nullable (could not get this to work yesterday) to both serialisers
Changed decodeSerializableElement to decodeNullableSerializableElement
Relevant changes below:
@ExperimentalSerializationApi
class ApiResponseSerializer<T&gt;(private val dataSerializer: KSerializer<T?&gt;) : KSerializer<ApiResponse<T&gt;&gt; {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(&quot;ApiResponseDataSerializer&quot;) {
val dataDescriptor = dataSerializer.descriptor
element(&quot;data&quot;, dataDescriptor.nullable)
element(&quot;errors&quot;, ErrorResponse.serializer().descriptor.nullable)
override fun deserialize(decoder: Decoder): ApiResponse<T&gt; =
decoder.decodeStructure(descriptor) {
var data: T? = null
var errors: List<ErrorResponse&gt;? = null
val listSerializer = ListSerializer(ErrorResponse.serializer()).nullable
loop@ while (true) {
when (val i = decodeElementIndex(descriptor)) {
0 -&gt; data = decodeNullableSerializableElement(descriptor, i, dataSerializer, null)
1 -&gt; errors = decodeNullableSerializableElement(descriptor, i, listSerializer, null)
CompositeDecoder.DECODE_DONE -&gt; break
else -&gt; throw SerializationException(&quot;Unknown index $i&quot;)
}
}
ApiResponse(data, errors)
}
override fun serialize(encoder: Encoder, value: ApiResponse<T&gt;) {
encoder.encodeStructure(descriptor) {
val listSerializer = ListSerializer(ErrorResponse.serializer())
encodeNullableSerializableElement(descriptor, 0, dataSerializer, value.data)
value.errors?.let {
encodeNullableSerializableElement(descriptor, 1, listSerializer, it)
}
}


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2021:00:06/16/21', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<kotlin><serialization>', 'Title': 'Having trouble with deserialising JSON nullable fields in Kotlin with custom decoder', 'ViewCount': 822, 'id': 67999441, 'user_AboutMe': '', 'user_AccountId': 204917.0, 'user_DisplayName': 'Brett', 'user_Reputation': 1419.0, 'user_Views': 188.0, 'user_id': 453406.0}}