Skip to content

kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlin.collections.HashMap #1450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Shabinder opened this issue May 3, 2021 · 9 comments
Assignees

Comments

@Shabinder
Copy link

Shabinder commented May 3, 2021

Describe the bug

  • kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlin.collections.HashMap

To Reproduce
If I execute the same Request from the same HTTP Client, the Request executes Successfully with the following config:

HttpClient {
                defaultRequest {
                    header("Authorization", "Bearer ${token.access_token}")
                }
            }

but when I add

install(JsonFeature)  {
                    serializer =  KotlinxSerializer(
            Json {
                isLenient = true
                ignoreUnknownKeys = true
            }
        )
}

and use like following, then following StackTrace is printed with said Exception.

HttpClient {
                defaultRequest {
                    header("Authorization", "Bearer ${token.access_token}")
                }
               install(JsonFeature)  {
                    serializer = kotlinxSerializer
                }
            }

Expected behavior
Response Should be parsed properly without any hashmap freeze.

StackTrace:

kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlin.collections.HashMap@2be0d88
    at 0   SpotiFlyer                          0x00000001080fb4bf kfun:kotlin.Throwable#<init>(kotlin.String?){} + 95 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Throwable.kt:23:37)
    at 1   SpotiFlyer                          0x00000001080f37cd kfun:kotlin.Exception#<init>(kotlin.String?){} + 93 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44)
    at 2   SpotiFlyer                          0x00000001080f3a3d kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 93 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44)
    at 3   SpotiFlyer                          0x000000010812afcd kfun:kotlin.native.concurrent.InvalidMutabilityException#<init>(kotlin.String){} + 93 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt:22:60)
    at 4   SpotiFlyer                          0x000000010812c7cf ThrowInvalidMutabilityException + 431 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt:93:11)
    at 5   SpotiFlyer                          0x0000000108223770 MutationCheck + 128
    at 6   SpotiFlyer                          0x000000010810d8b2 kfun:kotlin.collections.HashMap.<set-length>#internal + 82 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/collections/HashMap.kt:16:17)
    at 7   SpotiFlyer                          0x00000001081126b1 kfun:kotlin.collections.HashMap#addKey(1:0){}kotlin.Int + 1233 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/collections/HashMap.kt:292:36)
    at 8   SpotiFlyer                          0x000000010810eaa5 kfun:kotlin.collections.HashMap#put(1:0;1:1){}1:1? + 357 (/Users/teamcity2/buildAgent/work/11ac87a349af04d5/runtime/src/main/kotlin/kotlin/collections/HashMap.kt:68:21)
    at 9   SpotiFlyer                          0x0000000108684f43 kfun:kotlinx.serialization.json.internal.DescriptorSchemaCache#set(kotlinx.serialization.descriptors.SerialDescriptor;kotlinx.serialization.json.internal.DescriptorSchemaCache.Key<0:0>;0:0){0§<kotlin.Any>} + 771 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/SchemaCache.kt:23:58)
    at 10  SpotiFlyer                          0x00000001086852f0 kfun:kotlinx.serialization.json.internal.DescriptorSchemaCache#getOrPut(kotlinx.serialization.descriptors.SerialDescriptor;kotlinx.serialization.json.internal.DescriptorSchemaCache.Key<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}0:0 + 576 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/SchemaCache.kt:29:9)
    at 11  SpotiFlyer                          0x00000001086878c3 kfun:kotlinx.serialization.json.internal.StreamingJsonDecoder.getJsonElementIndex#internal + 899 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt:113:30)
    at 12  SpotiFlyer                          0x0000000108688288 kfun:kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeObjectIndex#internal + 664 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt:143:36)
    at 13  SpotiFlyer                          0x0000000108686e16 kfun:kotlinx.serialization.json.internal.StreamingJsonDecoder#decodeElementIndex(kotlinx.serialization.descriptors.SerialDescriptor){}kotlin.Int + 502 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt:75:30)
    at 14  SpotiFlyer                          0x0000000107e42de9 kfun:com.shabinder.common.models.spotify.Playlist.$serializer#deserialize(kotlinx.serialization.encoding.Decoder){}com.shabinder.common.models.spotify.Playlist + 8137
    at 15  SpotiFlyer                          0x000000010868304e kfun:kotlinx.serialization.json.internal#decodeSerializableValuePolymorphic@kotlinx.serialization.json.JsonDecoder(kotlinx.serialization.DeserializationStrategy<0:0>){0§<kotlin.Any?>}0:0 + 2798 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/Polymorphic.kt:63:29)
    at 16  SpotiFlyer                          0x00000001086860ca kfun:kotlinx.serialization.json.internal.StreamingJsonDecoder#decodeSerializableValue(kotlinx.serialization.DeserializationStrategy<0:0>){0§<kotlin.Any?>}0:0 + 202 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt:32:16)
    at 17  SpotiFlyer                          0x0000000108662261 kfun:kotlinx.serialization.json.Json#decodeFromString(kotlinx.serialization.DeserializationStrategy<0:0>;kotlin.String){0§<kotlin.Any?>}0:0 + 753 (/opt/buildAgent/work/b2fef8360e1bcf3d/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt:95:28)
    at 18  SpotiFlyer                          0x00000001086a87e9 kfun:io.ktor.client.features.json.serializer.KotlinxSerializer#read(io.ktor.client.call.TypeInfo;io.ktor.utils.io.core.Input){}kotlin.Any + 1081 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-features/ktor-client-json/ktor-client-serialization/common/src/io/ktor/client/features/json/serializer/**KotlinxSerializer.kt:**37:21)
    at 19  SpotiFlyer                          0x000000010860c0d5 kfun:io.ktor.client.features.json.JsonFeature.Feature.$install$lambda-1COROUTINE$1.invokeSuspend#internal + 2805 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-features/ktor-client-json/common/src/io/ktor/client/features/json/**JsonFeature.kt**:161:53)
    at 20  SpotiFlyer                          0x000000010860cb7a kfun:io.ktor.client.features.json.JsonFeature.Feature.$install$lambda-1COROUTINE$1.invoke#internal + 394 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-features/ktor-client-json/common/src/io/ktor/client/features/json/**JsonFeature.kt**:155:78)
    at 21  SpotiFlyer                          0x00000001085361e9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.$loop$<anonymous>_2COROUTINE$8.invokeSuspend#internal + 697 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:17:2)
    at 22  SpotiFlyer                          0x000000010853678d kfun:io.ktor.util.pipeline.SuspendFunctionGun.$loop$<anonymous>_2COROUTINE$8.invoke#internal + 269 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:16:23)
    at 23  SpotiFlyer                          0x0000000108534a9f kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1295 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:160:99)
    at 24  SpotiFlyer                          0x000000010853404f kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceed(){}1:0 + 415 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:116:13)
    at 25  SpotiFlyer                          0x0000000108534250 kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceedWith(1:0){}1:0 + 224 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:126:16)
    at 26  SpotiFlyer                          0x00000001085c8904 kfun:io.ktor.client.features.HttpCallValidator.Companion.$install$lambda-2COROUTINE$19.invokeSuspend#internal + 948 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/features/HttpCallValidator.kt:125:21)
    at 27  SpotiFlyer                          0x00000001085c91fa kfun:io.ktor.client.features.HttpCallValidator.Companion.$install$lambda-2COROUTINE$19.invoke#internal + 394 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/features/HttpCallValidator.kt:123:61)
    at 28  SpotiFlyer                          0x00000001085361e9 kfun:io.ktor.util.pipeline.SuspendFunctionGun.$loop$<anonymous>_2COROUTINE$8.invokeSuspend#internal + 697 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:17:2)
    at 29  SpotiFlyer                          0x000000010853678d kfun:io.ktor.util.pipeline.SuspendFunctionGun.$loop$<anonymous>_2COROUTINE$8.invoke#internal + 269 (/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-utils/common/src/io/ktor/util/pipeline/SuspendFunctionGun.kt:16:23)

Environment

  • Kotlin version: 1.4.32
  • Library version: 1.2.0
  • Kotlin platforms: Native(IOS)
  • Gradle version: 6.8
@Shabinder
Copy link
Author

Shabinder commented May 3, 2021

and as expected without adding a serializer , I get following Error and it confirms that adding KotlinxSerializer with Json causes the freezing issue:

io.ktor.client.call.NoTransformationFoundException: No transformation found: class io.ktor.utils.io.ByteChannelNative -> class com.shabinder.common.models.spotify.Playlist
with response from https://api.spotify.com/v1/playlists/0l88QNwuL9LCTFjzrTlstQ:
status: 200 OK
response headers: 
Access-Control-Allow-Origin: *
, Content-Type: application/json; charset=utf-8
, Alt-Svc: clear
, Content-Encoding: gzip
, access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
, Server: envoy
, Via: HTTP/2 edgeproxy, 1.1 google
, access-control-max-age: 604800
, access-control-allow-headers: Accept, App-Platform, Authorization, Content-Type, Origin, Retry-After, Spotify-App-Version, X-Cloud-Trace-Context, client-token, content-access-token
, Cache-Control: public, max-age=0
, Date: Mon, 03 May 2021 19:28:41 GMT
, x-robots-tag: noindex, nofollow
, access-control-allow-credentials: true
, Content-Length: 31197
, Strict-Transport-Security: max-age=31536000
, x-content-type-options: nosniff

@Shabinder
Copy link
Author

Shabinder commented May 3, 2021

WORKAROUND:

Everything works if i use like below:


        val response = httpClient.get<HttpResponse>("$BASE_URL/playlists/$playlistID")
        val jsonBody = response.readText()
        return Json{ignoreUnknownKeys = true}.decodeFromString(Playlist.serializer(),jsonBody)

So for now, I am continuing development by using the below extensions:


@OptIn(InternalSerializationApi::class)
suspend inline fun <reified T: Any> HttpClient.getData(
    urlString: String,
    block: HttpRequestBuilder.() -> Unit = {}
): T {
    val response = get<HttpResponse> {
        url.takeFrom(urlString)
        block()
    }
    val jsonBody = response.readText()
    return json.decodeFromString(T::class.serializer(),jsonBody)
}

@ThreadLocal
val json by lazy { Json {
    isLenient = true
    ignoreUnknownKeys = true
} }

@sandwwraith
Copy link
Member

Another workaround is to disable useAlternativeNames in Json configuration

@sandwwraith
Copy link
Member

@ThreadLocal
val globalJson = Json {
                isLenient = true
                ignoreUnknownKeys = true
            }

install(JsonFeature)  {
                    serializer =  KotlinxSerializer(globalJson)
}

should do the trick, too

@marcantoinefortier
Copy link

marcantoinefortier commented May 17, 2021

#1450 (comment)

I confirm this workaround is working!

Waiting for the actual fix to be released so we can safely update our internal libs to 1.2.1 1.2.2.

Thanks for #1484 @sandwwraith ❤️

@sandwwraith
Copy link
Member

@marcantoinefortier 1.2.1 is already released, so #1484 won't be there :(

@sven4all
Copy link

When can we expect the 1.2.2 update with this fix included? This issue is blocking some other library upgrades we should do in our project, so would be really nice if an release can be made in the near future.

@abhishekdewan101
Copy link

Another workaround is to disable useAlternativeNames in Json configuration

Can confirm that this works for me as well

@sandwwraith
Copy link
Member

@sven4all I'll see if that would be possible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants