MissingFieldException: 'body' field missing in GitHubRelease deserialization
Description
When initializing KCEF with GitHub releases download, I encountered a serialization error: 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
io.ktor.serialization.JsonConvertException: Illegal input: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:77)
at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1$2.emit(Emitters.kt:51)
at kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:111)
at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1.collect(SafeCollector.common.kt:109)
at kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:247)
at kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source)
at io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:97)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.ContentNegotiation$lambda$13$convertResponse(ContentNegotiation.kt:234)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.access$ContentNegotiation$lambda$13$convertResponse(ContentNegotiation.kt:1)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invokeSuspend(ContentNegotiation.kt:249)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invoke(ContentNegotiation.kt)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invoke(ContentNegotiation.kt)
at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invokeSuspend(KtorCallContexts.kt:104)
at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invoke(KtorCallContexts.kt)
at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invoke(KtorCallContexts.kt)
at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:179)
at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
at io.ktor.client.plugins.ReceiveError$install$1.invokeSuspend(HttpCallValidator.kt:149)
at io.ktor.client.plugins.ReceiveError$install$1.invoke(HttpCallValidator.kt)
at io.ktor.client.plugins.ReceiveError$install$1.invoke(HttpCallValidator.kt)
at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:86)
at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:87)
at dev.datlag.kcef.KCEFBuilder$Download$Transform$Companion$GitHub$1.transform(KCEFBuilder.kt:881)
at dev.datlag.kcef.step.fetch.PackageDownloader.downloadPackage(PackageDownloader.kt:30)
at dev.datlag.kcef.step.fetch.PackageDownloader$downloadPackage$1.invokeSuspend(PackageDownloader.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:124)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:95)
at kotlinx.serialization.json.Json.decodeFromString(Json.kt:149)
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:69)
... 40 more
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing
at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing
at dev.datlag.kcef.model.GitHubRelease.<init>(GitHubRelease.kt:6)
at dev.datlag.kcef.model.GitHubRelease$$serializer.deserialize(GitHubRelease.kt:6)
at dev.datlag.kcef.model.GitHubRelease$$serializer.deserialize(GitHubRelease.kt:6)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:69)
... 42 more
io.ktor.serialization.JsonConvertException: Illegal input: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:77)
at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1$2.emit(Emitters.kt:51)
at kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:111)
at io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1.collect(SafeCollector.common.kt:109)
at kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:247)
at kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source)
at io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:97)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.ContentNegotiation$lambda$13$convertResponse(ContentNegotiation.kt:234)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt.access$ContentNegotiation$lambda$13$convertResponse(ContentNegotiation.kt:1)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invokeSuspend(ContentNegotiation.kt:249)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invoke(ContentNegotiation.kt)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiationKt$ContentNegotiation$2$2.invoke(ContentNegotiation.kt)
at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invokeSuspend(KtorCallContexts.kt:104)
at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invoke(KtorCallContexts.kt)
at io.ktor.client.plugins.api.TransformResponseBodyHook$install$1.invoke(KtorCallContexts.kt)
at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:179)
at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
at io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
at io.ktor.client.plugins.ReceiveError$install$1.invokeSuspend(HttpCallValidator.kt:149)
at io.ktor.client.plugins.ReceiveError$install$1.invoke(HttpCallValidator.kt)
at io.ktor.client.plugins.ReceiveError$install$1.invoke(HttpCallValidator.kt)
at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:79)
at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:86)
at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:87)
at dev.datlag.kcef.KCEFBuilder$Download$Transform$Companion$GitHub$1.transform(KCEFBuilder.kt:881)
at dev.datlag.kcef.step.fetch.PackageDownloader.downloadPackage(PackageDownloader.kt:30)
at dev.datlag.kcef.step.fetch.PackageDownloader$downloadPackage$1.invokeSuspend(PackageDownloader.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:124)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:95)
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing at path: $
at kotlinx.serialization.json.Json.decodeFromString(Json.kt:149)
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:69)
... 40 more
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing
Caused by: kotlinx.serialization.MissingFieldException: Field 'body' is required for type with serial name 'dev.datlag.kcef.model.GitHubRelease', but it was missing
at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
at dev.datlag.kcef.model.GitHubRelease.<init>(GitHubRelease.kt:6)
at dev.datlag.kcef.model.GitHubRelease$$serializer.deserialize(GitHubRelease.kt:6)
at dev.datlag.kcef.model.GitHubRelease$$serializer.deserialize(GitHubRelease.kt:6)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:69)
... 42 more
Steps to reproduce
Use the following code in your desktop main() function:
package org.dsqrwym.standard
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.multiplatform.webview.util.addTempDirectoryRemovalHook
import dev.datlag.kcef.KCEF
import dev.datlag.kcef.KCEFBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.dsqrwym.shared.AppRoot
import java.io.File
import kotlin.math.max
fun main() = application {
addTempDirectoryRemovalHook()
Window(
onCloseRequest = ::exitApplication,
title = "Project",
) {
var restartRequired by remember { mutableStateOf(false) }
var downloading by remember { mutableStateOf(0F) }
var initialized by remember { mutableStateOf(false) }
val download: KCEFBuilder.Download = remember { KCEFBuilder.Download.Builder().github().build() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
KCEF.init(builder = {
installDir(File("kcef-bundle"))
/*
Add this code when using JDK 17.
Builder().github {
release("jbr-release-17.0.10b1087.23")
}.buffer(download.bufferSize).build()
*/
progress {
onDownloading {
downloading = max(it, 0F)
}
onInitialized {
initialized = true
}
}
settings {
cachePath = File("cache").absolutePath
}
}, onError = {
it?.printStackTrace()
}, onRestartRequired = {
restartRequired = true
})
}
}
if (!restartRequired) {
if (initialized) {
App()
} else {
AppRoot {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
LinearProgressIndicator(
progress = { downloading },
modifier = Modifier,
color = ProgressIndicatorDefaults.linearColor,
trackColor = ProgressIndicatorDefaults.linearTrackColor,
strokeCap = ProgressIndicatorDefaults.LinearStrokeCap,
)
Text(text = "Downloading $downloading%")
}
}
}
}
DisposableEffect(Unit) {
onDispose {
KCEF.disposeBlocking()
}
}
}
}
- Use KCEFBuilder.Download.Builder().github().build() as shown.
- Run the application and wait for initialization.
- The error occurs during deserialization of GitHub release data.
Expected Behavior
The body field in GitHubRelease should be optional (String? = null) to support releases that do not have a body. This would prevent deserialization failures.
Environment
- compose-webview-multiplatform version: 2.0.0
- JDK version: 11
- OS: Windows 11
- Kotlin version: 2.1.21
Thanks for your work on this project, make OPEN SOURCE great
I got the same issue, but I solved it.
You can see that the request URL is "https://api.github.com/repos/JetBrains/JetBrainsRuntime/releases/tags/jbr-release-17.0.12b1207.37." if you set breakpoints. When u go to browse the URL directly, you will receive the following response:
{ "message": "API rate limit exceeded for 43.132.141.13. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)", "documentation_url": "https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting" }
This is because GitHub limits requests when it is not in a logged-in status. See[Rate limits for the REST API](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28)) , So, just need to solve this problem.
Following code works for me:
val customClient = HttpClient {
followRedirects = true
install(ContentNegotiation) {
json(
Json {
ignoreUnknownKeys = true
})
}
install(HttpTimeout) {
// If the network speed is slow, you can increase this value appropriately.
requestTimeoutMillis = 60 * 1000
}
install(Auth) {
bearer {
loadTokens {
// token from https://github.com/settings/tokens
BearerTokens("ghp_xxxxxxxxxxxxxxxxxx", "ghp_xxxxxxxxxxxxxxxxxx")
}
}
}
}
KCEF.init(builder = {
download {
github {
release("jbr-release-17.0.12b1207.37")
}
client(client = customClient)
}
... other config
}
In addition, install(Auth) need dependency: implementation("io.ktor:ktor-client-auth:$ktor_version")
All right 👍🏻, thanks 🙏🏻 so much