https://kotlinlang.org logo
Join Slack
Powered by
# serialization
  • f

    Fred Bowker

    09/03/2025, 4:28 PM
    I’m getting the following warning “this declaration is opt-in and its usage should be marked with @kotlinx.serialization.InternalSerializationApi” whenever a class is marked with @Serializable, not sure why this warning is showing up as Serializable isn’t experimental opt-in
  • f

    Fred Bowker

    09/03/2025, 5:05 PM
    reading through some previous messages and I can hide the warning by adding a lint with
    Copy code
    <?xml version="1.0" encoding="UTF-8"?>
    <lint>
        <issue id="UnsafeOptInUsageError" severity="ignore">
            <option name="opt-in" value="kotlinx.serialization.InternalSerializationApi" />
        </issue>
    </lint>
    but not sure why this is necessary, or whether this is an issue with intellij
  • v

    v79

    09/14/2025, 4:21 PM
    I may be wrong, but I think kotlin.time.Instant and kotlinx.datetime.Instant serialize differently. My API sends a kotlinx.datetime.Instant and it appears in Json as "2025-09-06T103224.608Z" . I think. Maybe. Can anyone confirm if the two Instant classes serialize differently?
    h
    • 2
    • 5
  • u

    ursus

    09/18/2025, 10:52 AM
    Is there a way to have a sort of
    Unknown
    sealed class child, that will be a fallback when all other classes don't match? (With annotations only? I know I can have a custom serializer a wire it up manually)
    Copy code
    @Serializable
    sealed class Item {
    
       @SerialName("A")
       @Serializable
       data class ChildA(..) : Item()
    
       @Serializable
       data class Unknown : Item() <--------
    }
    m
    • 2
    • 2
  • m

    Martin Scotta

    09/24/2025, 5:28 AM
    Hi all, we are seeing some serialization issues and we would like to hear from leaders and the broad community. Full details here: https://github.com/temporalio/sdk-java/issues/2665 The TLDR is our kotlin project is having challenges integrating with Jackson/Gson serialization. Are these compatible to each other? Is it possible to write a custom Jackson/Gson adapter that entirely delegates encode/decode to kotlin?
    g
    • 2
    • 15
  • s

    Said Shatila

    10/01/2025, 5:48 PM
    Hey has anyone faced this issue error while building ?
    🧵 2
    • 1
    • 1
  • r

    Richard Schielek

    10/01/2025, 10:30 PM
    Is there a more elegant way of doing this? I know a sealed super type with polymorphic serialization would also do it, but it feels awkward if there is only one implementation.
    Copy code
    import kotlinx.serialization.EncodeDefault
    import kotlinx.serialization.Required
    import kotlinx.serialization.Serializable
    import kotlinx.serialization.json.Json
    
    @Serializable
    data class SomeEvent(
        val subject: String,
    ) {
        @EncodeDefault
        @Required
        private var type = "SOME_EVENT"
    
        init {
            require(type == "SOME_EVENT") { "'type' field of SomeEvent must be 'SOME_EVENT' but was '$type'" }
        }
    }
    
    fun main() {
        println(Json.encodeToString(SomeEvent("foo"))) // {"subject":"foo","type":"SOME_EVENT"}
        println(Json.decodeFromString<SomeEvent>("""{"subject": "foo", "type": "SOME_EVENT"}""")) // SomeEvent(subject=foo)
        println(
            try {
                Json.decodeFromString<SomeEvent>("""{"subject": "bar", "type": "OTHER_EVENT"}""")
            } catch (e: IllegalArgumentException) {
                e.message
            }
        ) // 'type' field of SomeEvent must be 'SOME_EVENT' but was 'OTHER_EVENT'
    }
    e
    • 2
    • 4
  • j

    Joaquim Puyo

    10/06/2025, 6:55 AM
    Hello, In a Kotlin multiplatform SDK, when trying to send a POST request and building http request body, I have some random crash EXC_BAD_ACCESS(KERN_INVALID_ADDRESS)
    Copy code
    Thread
    0x6bea58 serialize + 11 (CollectRequestBodyDto.kt:11)
    0x6882e4 encodeSerializableValue + 69 (StreamingJsonEncoder.kt:69)
    0x6623e8 serialize + 69 (CollectionSerializers.kt:69)
    0x6882e4 encodeSerializableValue + 69 (StreamingJsonEncoder.kt:69)
    0x6bdda8 serialize + 6 (CollectRequestBodyDto.kt:6)
    0x6882e4 encodeSerializableValue + 69 (StreamingJsonEncoder.kt:69)
    0x678c68 encodeToString + 32 (JsonStreams.kt:32)
    0x675f40 invokeSuspend + 95 (SerialFormat.kt:95)
    0x676208 serialize + 54 (KotlinxSerializationConverter.kt:54)
    0x63eef4 invokeSuspend + 40 (ContentConverter.kt:40)
    0x640000 invoke + 142 (ContentNegotiation.kt:142)
    0x6dc9c4 invoke + 1 ([K][Suspend]Functions:1)
    0x635fa4 invokeSuspend + 78 (KtorCallContexts.kt:78)
    0x6361c8 invoke + 77 (KtorCallContexts.kt:77)
    0x6d6a0c invoke + 1 ([K][Suspend]Functions:1)
    0x6032ac loop + 120 (SuspendFunctionGun.kt:120)
    0x602f8c proceed + 78 (SuspendFunctionGun.kt:78)
    0x62b8c0 invokeSuspend + 41 (PipelineContext.kt:41)
    0x62bbd0 invoke + 149 (HttpCallValidator.kt:149)
    0x6d6a0c invoke + 1 ([K][Suspend]Functions:1)
    0x6032ac loop + 120 (SuspendFunctionGun.kt:120)
    0x602f8c proceed + 78 (SuspendFunctionGun.kt:78)
    0x6316d0 invokeSuspend + 41 (PipelineContext.kt:41)
    0x631918 invoke + 40 (HttpRequestLifecycle.kt:40)
    0x6dc8f0 invoke + 1 ([K][Suspend]Functions:1)
    0x631c20 invokeSuspend + 27 (HttpRequestLifecycle.kt:27)
    0x632130 invoke + 20 (HttpRequestLifecycle.kt:20)
    0x6d6bb4 invoke + 1 ([K][Suspend]Functions:1)
    0x631804 invoke + 40 (HttpRequestLifecycle.kt:40)
    0x6d6a0c invoke + 1 ([K][Suspend]Functions:1)
    0x6032ac loop + 120 (SuspendFunctionGun.kt:120)
    0x602f8c proceed + 78 (SuspendFunctionGun.kt:78)
    0x603158 execute + 98 (SuspendFunctionGun.kt:98)
    0x60181c execute + 74 (Pipeline.kt:74)
    0x61c7e8 invokeSuspend + 193 (HttpClient.kt:193)
    0x63c414 invokeSuspend + 190 (HttpClient.kt:190)
    0x6d1510 invokeSuspend + 111 (HttpStatement.kt:111)
    0x6d17c8 invoke + 42 (TheWireRemoteDataSource.kt:42)
    0x6dc8f0 invoke + 1 ([K][Suspend]Functions:1)
    0x6d0d18 invokeSuspend + 67 (TheWireRemoteDataSource.kt:67)
    0x6d09c0 invokeSuspend + 65 (TheWireRemoteDataSource.kt:65)
    0x6d0be4 sendEvents + 63 (TheWireRemoteDataSource.kt:63)
    0x6cfd58 invokeSuspend + 94 (TheWireQueueEventsCollector.kt:94)
    0x6cffc8 sendRequest + 97 (TheWireQueueEventsCollector.kt:97)
    0x6d01e4 invokeSuspend + 72 (TheWireQueueEventsCollector.kt:72)
    0x6d0720 invoke + 66 (TheWireQueueEventsCollector.kt:66)
    0x6d6938 invoke + 1 ([K][Suspend]Functions:1)
    0x5281e4 invokeSuspend + 72 (IntrinsicsNative.kt:72)
    0x526fa8 resumeWith + 50 (ContinuationImpl.kt:50)
    0x5c605c run + 1 (Result.kt:1)
    0x5c6f60 run + 115 (LimitedDispatcher.kt:115)
    0x5d182c invokeSuspend + 106 (MultithreadedDispatchers.kt:106)
    0x526fa8 resumeWith + 50 (ContinuationImpl.kt:50)
    0x5c605c run + 1 (Result.kt:1)
    0x5a6108 processNextEvent + 15 (ObjectiveCUtils.kt:15)
    0x5ce1e0 runBlocking + 49 (EventLoop.common.kt:49)
    0x5d1eb0 $<bridge-UNN>invoke(){} + 119 (MultithreadedDispatchers.kt:119)
    0x6d4d08 invoke + 1 ([K][Suspend]Functions:1)
    0x785fe0 Worker::processQueueElement(bool) + 6900
    0x785ab0 (anonymous namespace)::workerRoutine(void*) + 5572
    0x606c _pthread_start + 136
    0x10d8 thread_start + 8
    I have omitted some fields here, but basically it seems that the crash is produced when trying to serialize the sealed class 'Default':
    Copy code
    @Serializable
    internal data class CollectRequestBodyDto(
        @SerialName("events") val events: List<EventDto>
    )
    
    @Serializable
    internal data class EventDto(
        ...
        @SerialName("data") val data: DataDto,
    )
    
    
    @Serializable
    internal sealed class DataDto {
        @Serializable
        data class Default(
                @SerialName("category") val category: String? = null,
                @SerialName("event") val event: String? = null,
                ...
        ) : DataDto()
    
        @Serializable
        data class Search(
            ...
        ) : DataDto()
    }
    Looking at the stack trace, it seems that the crash is located at this line: https://github.com/Kotlin/kotlinx.serialization/blob/71b5d5ee99f953b60756c4aaa2ac8e12c3fae605/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt#L69
    Copy code
    override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
            encodePolymorphically(serializer, value) { discriminatorName, serialName ->
                polymorphicDiscriminator = discriminatorName   --> Crash is located here
                polymorphicSerialName = serialName
            }
        }
    To provide more context, this is working without issues in Android and failing randomly in iOS, and it is executed inside a background process that is sending analytics events. To solve the situation, I will try to avoid sealed classes and build the json in some other way (like buildJsonObject), but I would like to know any hint about the root cause of this issue. This is working for 99% of the users, but randomly failing from time to time. I am not able to reproduce the issue but I see error logs in crashlytics.... Any hint? Thanks!
  • m

    Md Anas Shikoh Shikoh

    10/06/2025, 9:56 AM
    Copy code
    @Keep
    data class RatingData(
        @SerializedName("show_nudge") val showNudge: Boolean,
        @SerializedName("is_app_rated") val isAppRated: Boolean,
    )
    this is my response class I wanted to know if backend sends null in anyone of these values, right now my app is not crashing but from what i know it should crash. Anyone has any idea about this, i think this is something related to Boolean because for other types it definitely crashes.
  • l

    Lilian GALLON

    10/08/2025, 7:22 AM
    Hi there, is there a way to change the way an Enum is serialized / deserialized when you can't modify it? I want to change the way the deserialization works to transform an unknown enum value to "MyEnum.OTHER" instead of throwing an exception. I implemented my own KSerializer(MyEnum), registered it in
    Json { serializersModule = SerializersModule { contextual(MyEnum::class, MyEnumSerializer) } }
    , but kotlinx.serialiaztion keeps using
    kotlinx.serialization.internal.EnumSerializer
    instead of the serializer I registered. Is there a way to force the use of my serializer ?
    ✅ 1
    e
    • 2
    • 2
  • t

    Travis Haagen

    10/10/2025, 10:58 PM
    Hello! I put up a PR to add support for "untagged null values in CBOR", and was hoping to discuss how it could potentially move forward. Untagged null is supported by the CBOR spec and needed for a project I am working on. https://github.com/Kotlin/kotlinx.serialization/pull/3074 cc: @Filipp Zhinkin
    f
    r
    • 3
    • 3
  • b

    Bernhard

    10/16/2025, 2:01 PM
    is there a reason why xml serialization is not part of kotlinx but ktor?
    h
    s
    • 3
    • 3
  • s

    Slackbot

    10/22/2025, 10:59 AM
    This message was deleted.
    h
    c
    • 3
    • 2
  • c

    Colton Idle

    10/22/2025, 6:41 PM
    I'm using kotlinx.serialization in my android library (first time developing a library). Does anyone know if I need to supply any r8 rules for consumers of the library? I'm not proguarding/r8ing my library, but if an app uses r8 and uses my library will it still know to retain those Serialized fields? according to the docs https://github.com/Kotlin/kotlinx.serialization?tab=readme-ov-file#android i shouldn't have to add anything in my app, but now I'm curious if its any different if its an android library?
    e
    • 2
    • 3
  • c

    CLOVIS

    10/25/2025, 1:17 PM
    Is there an easy way to write something like
    Copy code
    @Serializable
    data class Foo(
        val date: @SerializeAsUnixSeconds Instant,
    )
    where it would serialize as
    Copy code
    data class Foo(
        val date: Int, // number of seconds since UNIX epoch
    )
    ? I know I could create a custom serializer for
    Foo
    , but there are many classes and fields where I need this and I don't want to create custom serializers for all of them. (same question for serializing a
    Duration
    as an
    Int
    number of seconds)
    h
    e
    +3
    • 6
    • 16
  • b

    Bernhard

    10/30/2025, 12:56 PM
    how do I serialize/deserialize an arbitrary JSON object? I've got a field that can have arbitrarily nested JSON data answer: MapString, JsonElement?
    ✅ 1
    r
    • 2
    • 1
  • c

    CLOVIS

    10/30/2025, 8:06 PM
    Copy code
    interface Foo
    
    @Serializable
    data object Bar : Foo
    // Impossible to make this class serializable because its parent is not serializable and does not have exactly one constructor without parameters
    I'm surprised this is forbidden. I would have expected it to serialize correctly as an empty JSON object.
    ➕ 1
    e
    • 2
    • 2
  • c

    CLOVIS

    10/31/2025, 4:27 PM
    Is it safe to call
    decodeString()
    and then if it throws an exception attempt to
    decodeXXX()
    again? I have some data that is sometimes encoded in a String.
    e
    • 2
    • 9
  • c

    CLOVIS

    11/01/2025, 5:30 PM
    I have a module
    core
    that declares some core data types, and another module
    feat
    that provides more features around them. In particular,
    feat
    provides a custom KotlinX.Serialization format. Still, I want
    core
    data types to be serializable in all formats. What I've done: •
    core
    has an
    implementation
    dependency on
    kotlinx-serialization-core
    •
    core
    data types have
    @Serializable(with = …)
    with a handwritten serializer. Do I need the serialization plugin on that module?
    👌 1
    e
    • 2
    • 1
  • z

    Zyle Moore

    11/05/2025, 2:15 AM
    I have a type hierarchy made of interfaces. I also have some data classes at the deepest point. Is there a way to easily or quickly register all of the data classes as all of the interfaces?
    e
    • 2
    • 4
  • c

    CLOVIS

    11/11/2025, 9:34 PM
    What's the correct way to declare serializers? I have a class
    Copy code
    @Serializable(with = ObjectId.Serializer::class)
    class ObjectId : Comparable<ObjectId> {
        …
    
        class Serializer : KSerializer<ObjectId> {
    		override val descriptor: SerialDescriptor
    			get() = PrimitiveSerialDescriptor("opensavvy.ktmongo.bson.types.ObjectId", PrimitiveKind.STRING)
    
    		@LowLevelApi
    		override fun serialize(encoder: Encoder, value: ObjectId) {
    			encoder.encodeString(value.hex)
    		}
    
    		override fun deserialize(decoder: Decoder): ObjectId =
    			decoder.decodeString().let(::ObjectId)
    	}
    }
    and the code (in another module):
    Copy code
    val decoder = BsonDecoder(EmptySerializersModule(), this)
    		return decoder.decodeSerializableValue(serializer(type) as KSerializer<T?>)
    where
    BsonDecoder : kotlinx.serialization.encoding.Decoder
    , but on non-JVM platforms I get:
    Copy code
    kotlinx.serialization.SerializationException: Serializer for class 'ObjectId' is not found.
    Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
    To get enum serializer on Kotlin/Native, it should be annotated with @Serializable annotation.
    To get interface serializer on Kotlin/Native, use PolymorphicSerializer() constructor function.
    The serialization plugin is applied to both modules. I see I can explicitly specify it with:
    Copy code
    val module = SerializersModule {
    			contextual(ObjectId::class, ObjectId.Serializer())
    		}
    
    		val decoder = BsonDecoder(module, this)
    		return decoder.decodeSerializableValue(module.serializer(type) as KSerializer<T?>)
    (even though the type is NOT used with
    @Contextual
    )—won't this mean that this code will break with user-provided types, though? I can't hardcode all the serializers that exist.
    e
    j
    • 3
    • 30
  • s

    Sebastian Schuberth

    11/13/2025, 11:52 AM
    What's the recommended practice to build a
    descriptor
    for a serializer that can deserialize from either a string or object? I was previously using
    buildSerialDescriptor(serialName, SerialKind.CONTEXTUAL) { ... }
    but I just learned from its docs that its use is discouraged in favor of
    buildClassSerialDescriptor
    , but that doe snot allow me to declare that the deserializer is contextual...
    e
    p
    • 3
    • 7
  • c

    CLOVIS

    11/26/2025, 7:02 PM
    Is there a way to ensure
    serializer(foo: KType)
    finds the serializer on all platforms? From what I understand, it uses reflection on the JVM, and fails on other platforms. If there was a way to declare a
    SerializerModule
    as "the plugin should automatically add all the classes it can find" I think that could solve the problem? I can't use the
    serializer<T>()
    reified function because it is in a function defined in an interface, so it can't be
    inline
    .
  • c

    CLOVIS

    11/26/2025, 8:16 PM
    Why is there no
    serializerOrNull<T>()
    function?
    ➕ 1
  • c

    CLOVIS

    11/26/2025, 8:30 PM
    I don't understand the algorithm for
    serializer(foo: KType)
    . I have this test code:
    Copy code
    test("Access a serializer that doesn't exist on all platforms") {
    		check(serializerOrNull(typeOf<Foo>()) == null) { "The class Foo is not serializable, this code shouldn't find a serializer" }
    	}
    
    	test("Access a serializer that exists on all platforms") {
    		check(serializerOrNull(typeOf<Profile>()) != null) { "The class Profile is serializable, this code should find a serializer" }
    	}
    
    	test("Access a serializer for ObjectId on all platforms") {
    		check(serializerOrNull(typeOf<ObjectId>()) != null) { "The class ObjectId is serializable, this code should find a serializer" }
    	}
    
    	test("Access a serializer for Foo2 on all platforms") {
    		check(serializerOrNull(typeOf<Foo2>()) != null) { "The class Foo2 is serializable, this code should find a serializer" }
    	}
    with the types:
    Copy code
    @Serializable
    data class Profile(
    	val name: String,
    	val age: Int,
    )
    
    class Foo(val a: Int)
    and in another module, that has the Serialization plugin:
    Copy code
    @Serializable(with = ObjectId.Serializer::class)
    class ObjectId : Comparable<ObjectId> {
    
        class Serializer : KSerializer<ObjectId> { … }
    }
    
    @Serializable
    class Foo2(val a: Int)
    and I get the result: • Serializer of `Foo`: OK on all platforms (returns
    null
    ) • Serializer of
    Profile
    : OK on all platforms (returns non-
    null
    ) • Serializer of
    ObjectId
    : Fails on non-JVM platforms (returns
    null
    ) • Serializer of `Foo2`: OK on all platforms (returns non-
    null
    ) So I guess that means
    serializer(KType)
    cannot find classes with a custom serializer? That's very unfortunate.
    • 1
    • 4
  • e

    eygraber

    12/01/2025, 7:58 AM
    Is there a way to indicate that all types in a sealed hierarchy should be serializable without annotating all of them?
  • j

    joseph_ivie

    12/01/2025, 6:30 PM
    Should
    Copy code
    public val SerialDescriptor.capturedKClass: KClass<*>?
    have a
    when
    case for
    WrappedSerialDescriptor
    ? I'd like to have a type whose default serializer is to be contextual with a fallback to a basic string mode.
  • i

    iseki

    12/04/2025, 6:31 AM
    Should we implement check during implement the Encoder/Decoder? Such as the
    decode*Element
    require the
    descriptor
    keep equals with
    beginStructure
    , should we do an explicit check? I found the JSON format doesn't do it.
  • j

    João Silva

    12/04/2025, 11:56 AM
    Hi guys! I'm currently migrating from Moshi to kotlin Serialization and was wondering if there is an easier solution for a polymorphic issue I'm facing. For the following:
    Copy code
    sealed interface Animal {
        val type: String
    }
    data class Cat(override val type: String) : Animal
    data class Dog(override val type: String) : Animal
    If I wanted to deserialize different "type values" into the same class, using moshi it would be a simple:
    Copy code
    internal object AnimalJsonAdapter : JsonAdapter.Factory by PolymorphicJsonAdapterFactory
        .of(Animal::class.java, "type")
        .withSubtype(Cat::class.java, "cat")
        .withSubtype(Dog::class.java, "labradoodle")
        .withSubtype(Dog::class.java, "greyhound")
    To achieve the same, using serialization, I could only find this approach:
    Copy code
    @Serializable
    sealed interface Dog : Animal
    
    @SerialName("labradoodle")
    @Serializable
    data class Labradoodle(override val type: String) : Dog
    
    @SerialName("greyhound")
    @Serializable
    data class Greyhound(override val type: String) : Dog
    But this results in a lot of duplicated classes if I have multiple possible types. Does any one know of a better solution?
    e
    a
    • 3
    • 5
  • j

    Joshua Hansen

    12/05/2025, 10:34 PM
    When writing a custom serializer for class, do I have to write two identical serializers for nullable and non-nullable? I have a custom serializer
    MyClassSerializer : KSerializer<MyClass>
    but I'm working with a
    Map<String, MyClass?>
    and I can't figure out how to manually specify the serializer for the map