hallvard
07/31/2025, 8:40 AMNathan Fallet
07/31/2025, 10:50 PMDumitru Preguza
08/03/2025, 6:43 PMError Domain=NSURLErrorDomain Code=-1011 "There was a bad response from the server." UserInfo={NSErrorFailingURLStringKey=<ws://test.com/rpc>, NSErrorFailingURLKey=<ws://test.com/rpc>, _NSURLLErrorWebSocketHandshakeFailureReasonKey=0, NSLocalizedDescription=There was a bad response from the server.}
Thread in Slack ConversationS.
08/04/2025, 1:45 PMcredentials include
for js clients to the cookies section. it takes some digging on slack to figure out why it doesn't work out of the box
(https://github.com/ktorio/ktor/pull/4793, https://youtrack.jetbrains.com/issue/KTOR-539/Ability-to-use-browser-cookie-storage#focus=Comments-27-4775173.0-0)Emanuele Iannuzzi
08/05/2025, 10:17 AMAuthorization
header following the Bearer
scheme)?
Header-based auth isn't profitable in the case of WebSockets, as the clients don't usually expose methods to provison such headers during the preflight HTTP request (in accordance to the WS standard)Kjartan
08/06/2025, 12:05 PMcall
property which as far as I understand does what I want:
call.launch(Dispatchers.IO) {
runCatching {
// some "long running" side effect doing updates in the db that should keep running after the response has been sent back to the client.
}.onFailure { error ->
// catch to avoid failing the parent coroutine and log properly
}
}
Is this considered "best practice" for my task? What about launching the coroutine in a new scope not related to the call/route scope:
CoroutineScope(Dispatchers.IO).launch {
// same as above
}
What is considered best practice?Gustavo Cesário
08/07/2025, 1:57 AMpost("/payments") {
try {
val request = call.receive<PaymentRequest>()
QueueService.addPaymentRequestToQueue(request)
call.respond(HttpStatusCode.Accepted)
} catch (e: Exception) {
call.respond(HttpStatusCode.InternalServerError, "Error processing payment request: ${e.message}")
}
}
• I already tried to wrap QueueService.addPaymentRequestToQueue in launch {}
.
• There are other coroutines running at the same time in my application.
I'm new to coroutines and ktor, so I'm afraid that I might have messed something with the dispatchers and how I'm creating the coroutines. What could I do to investigate what the problem is?Dzmitry Neviadomski
08/08/2025, 12:47 PMmultipart/form-data
with HttpClient
without running out of memory.
I've summarized all the different methods I could find as of Ktor 3.2.3
in the first message in thread.
The official documentation primarily highlights the first method (using a ByteArray
), which seems unsuitable for large files due to its high memory consumption.
From the streaming options I've listed, which is considered the most reliable and efficient?
Also, would it be helpful to file a documentation issue to add examples for this use case?
Any insights would be greatly appreciated. Thanks!Pim
08/08/2025, 4:30 PM{…}
always follows a /
(end of a path segment). Is this a requirement or can the tailcard be used anywhere in the path?
For example, a route like /test{…}
. I’ve tested this and it works precisely as I want; I just like to confirm that this is also intended and will not be patched later.Tristan
08/08/2025, 11:33 PMClosedByteChannelException
.
I want to add a feature similar to what Cronet offers, where the plugin can save the partially downloaded file and resume the download using Content-Range. This would only work if the server or CDN supports it.
I'm not sure how difficult this task will be. My main question is whether it's possible for a plugin to capture this specific type of error. If anyone has insights on this, I'd appreciate the help!Alex Styl
08/10/2025, 2:28 PMmudasar187
08/13/2025, 8:40 AMmessage: A task raised an exception. Task: io.netty.channel.AbstractChannel$AbstractUnsafe$8@7a8dccce
stacktrace: java.util.concurrent.RejectedExecutionException: event executor terminated at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:1005) at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:388) at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:381) at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:907) at io.netty.util.concurrent.SingleThreadEventExecutor.execute0(SingleThreadEventExecutor.java:873) at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:863) at io.netty.channel.DefaultChannelPipeline.destroyUp(DefaultChannelPipeline.java:816) at io.netty.channel.DefaultChannelPipeline.destroy(DefaultChannelPipeline.java:801) at io.netty.channel.DefaultChannelPipeline.access$700(DefaultChannelPipeline.java:45) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelUnregistered(DefaultChannelPipeline.java:1411) at io.netty.channel.DefaultChannelPipeline.fireChannelUnregistered(DefaultChannelPipeline.java:780) at io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:692) at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:148) at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:141) at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:507) at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:182) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1073) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:1583)
What could be causing this? I'm trying to understand why we didn't get this before but started getting it with the latest version of ktor 3.2.3
We have alarms for our applications and often get this WARNING alarm which is quite annoying. Anything I can do to resolve this?Bruce Hamilton
08/14/2025, 12:05 PMSaid Shatila
08/14/2025, 2:23 PMFirst url --> <https://main-a.com>
Second url --> <https://main-b.com>
and I am using Ktor --> I know I can build a new
url {
host = <https://main-b.com>
encodedPath = v1
protocol = URLProtocol.HTTPS
}
and I have my default request in my networkmodule.kt
defaultRequest {
param.append("","")
param.append("","")
......
}
So I have a bunch of default parameters so let's say I am doing a normal call just adding the endpoint nothing will change but if I created a new urlBuilder all of the params are being override.
What could be the solution for thisS.
08/15/2025, 3:09 PMbuszi0809
08/19/2025, 7:45 AMsuspend
in the Default Request plugin? I want to add some header to the request from a local storage, and the query to that storage is based on coroutines. Thought Ktor as the superior client would handle that easily. To my suprise this won't compile because the builder is missing the suspend
modifier. Why is that?
install(DefaultRequest) {
header("some key", someRepo.getValue())
}
Where someRepo.getValue()
is suspend function.
Based on implementation of Default Request plugin I've managed to create such a bypass for that when building the HttpClient:
.apply {
requestPipeline.intercept(HttpRequestPipeline.Before) {
header("some key", someRepo.getValue())
}
}
Carter
08/19/2025, 11:50 AMursus
08/19/2025, 7:12 PMtestApplication
, should I wrap it in runTest { .. }
or not? Both seem to work
@Test fun foo() = runTest {
testApplication {
//
}
}
vs
@Test fun foo() = testApplication {
//
}
Daniel Pitts
08/19/2025, 10:23 PM3.2.3
with SSE.
Caused by: kotlinx.serialization.SerializationException: Serializer for class 'ClientSSESession' is not found.
For some reason, the private suspend inline fun <reified T> HttpClient.processSession
method is trying to create a body of type ClientSSESession
, which seems wrong to me, but i don't really know.
statement.body<T, Unit> { session ->
sessionDeferred.complete(session)
}
Ryan Woodcock
08/20/2025, 6:36 AMLukas Anda
08/20/2025, 10:31 AM"null"
as null value? This may come for any object not only strings. I was thinking about a custom serializer but I can't find a proper guide for thisMario Palka
08/20/2025, 12:17 PMShiinaKin
08/20/2025, 1:08 PMdata class NetworkError(
val type: NetworkErrorType,
val originalException: Throwable? = null
)
class NetworkHandleConfig {
lateinit var onNetworkError: ((NetworkError) -> Unit)
}
val NetworkHandle = createClientPlugin("NetworkHandle", createConfiguration = ::NetworkHandleConfig) {
val onNetworkError = pluginConfig.onNetworkError
on(Send) { context ->
try {
proceed(context)
} catch (e: CancellationException) {
throw e
} catch (e: HttpRequestTimeoutException) {
val networkError = NetworkError(
type = NetworkErrorType.TIMEOUT_ERROR,
originalException = e
)
onNetworkError(networkError)
context.executionContext.cancel(CancellationException("Request cancelled due to timeout"))
proceed(context)
} catch (e: Exception) {
val networkError = when {
e.message?.contains("offline", ignoreCase = true) == true ||
e.message?.contains("connection", ignoreCase = true) == true ||
e.message?.contains("unreachable", ignoreCase = true) == true -> {
NetworkError(
type = NetworkErrorType.CONNECTION_ERROR,
originalException = e
)
}
e.message?.contains("timeout", ignoreCase = true) == true -> {
NetworkError(
type = NetworkErrorType.TIMEOUT_ERROR,
originalException = e
)
}
e.message?.contains("dns", ignoreCase = true) == true ||
e.message?.contains("host", ignoreCase = true) == true -> {
NetworkError(
type = NetworkErrorType.DNS_ERROR,
originalException = e
)
}
e.message?.contains("ssl", ignoreCase = true) == true ||
e.message?.contains("tls", ignoreCase = true) == true ||
e.message?.contains("certificate", ignoreCase = true) == true -> {
NetworkError(
type = NetworkErrorType.SSL_ERROR,
originalException = e
)
}
else -> {
NetworkError(
type = NetworkErrorType.UNKNOWN_ERROR,
originalException = e
)
}
}
onNetworkError(networkError)
context.executionContext.cancel(CancellationException("Request cancelled due to network error"))
proceed(context)
}
}
onRequest { request, _ ->
request.executionContext.invokeOnCompletion { cause ->
if (cause?.cause is HttpRequestTimeoutException) {
val networkError = NetworkError(
type = NetworkErrorType.TIMEOUT_ERROR,
originalException = cause.cause
)
onNetworkError(networkError)
}
}
}
}
install(HttpTimeout) {
requestTimeoutMillis = 3000
}
Anton Yalyshev [JB]
08/21/2025, 10:22 AMursus
08/21/2025, 7:38 PMtestApplication
at test time?
class FooTest {
...
private val scheduler = TestCoroutineScheduler()
private val standardTestDispatcher = StandardTestDispatcher(scheduler)
private val dispatcherProvider = TestDispatcherProvider(standardTestDispatcher) <---------
private val appDatabase = InMemoryDatabase(...)
private val fooDao = FooDao(dispatcherProvider, appDatabase.fooQueries) <-----------
@Test
fun foo() = testApplication(standardTestDispatcher) { <---------
turbineScope {
val fooTurbine = fooDao.foo.testIn(this)
assertThat(fooTurbine.awaitItem()).isNull()
fooDao.saveFoo(..)
assertThat(fooTurbine.awaitItem()).isNotNull()
fooTurbine.cancelAndEnsureAllEventsConsumed()
}
}
}
class TestDispatcherProvider(standardTestDispatcher: TestDispatcher) : DispatcherProvider {
override val io: CoroutineDispatcher = standardTestDispatcher
override val main: CoroutineDispatcher = standardTestDispatcher
override val default: CoroutineDispatcher = standardTestDispatcher
}
crashes with
java.lang.IllegalStateException: Detected use of different schedulers. If you need to use several test coroutine dispatchers, create one `TestCoroutineScheduler` and pass it to each of them.
at kotlinx.coroutines.test.TestCoroutineSchedulerKt.checkSchedulerInContext(TestCoroutineScheduler.kt:257)
at kotlinx.coroutines.test.TestCoroutineScheduler.registerEvent$kotlinx_coroutines_test(TestCoroutineScheduler.kt:68)
at kotlinx.coroutines.test.StandardTestDispatcherImpl.dispatch(TestCoroutineDispatchers.kt:150)
at kotlinx.coroutines.internal.DispatchedContinuationKt.safeDispatch(DispatchedContinuation.kt:254)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:318)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:170)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
at io.ktor.server.testing.TestApplicationKt.runTestApplication(TestApplication.kt:534)
at io.ktor.server.testing.TestApplicationKt$testApplication$1.invokeSuspend(TestApplication.kt:517)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:42)
at io.ktor.test.dispatcher.TestCommonKt$runTestWithRealTime$1.invokeSuspend(TestCommon.kt:40)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$2$1$1.invokeSuspend(TestBuilders.kt:317)
Caused by:
java.lang.IllegalStateException: Detected use of different schedulers. If you need to use several test coroutine dispatchers, create one `TestCoroutineScheduler` and pass it to each of them.
at kotlinx.coroutines.test.TestCoroutineSchedulerKt.checkSchedulerInContext(TestCoroutineScheduler.kt:257)
at kotlinx.coroutines.test.TestCoroutineScheduler.registerEvent$kotlinx_coroutines_test(TestCoroutineScheduler.kt:68)
at kotlinx.coroutines.test.StandardTestDispatcherImpl.dispatch(TestCoroutineDispatchers.kt:150)
at kotlinx.coroutines.internal.DispatchedContinuationKt.safeDispatch(DispatchedContinuation.kt:254)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:318)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:170)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
at io.ktor.server.testing.TestApplicationKt.runTestApplication(TestApplication.kt:534)
at io.ktor.server.testing.TestApplicationKt$testApplication$1.invokeSuspend(TestApplication.kt:517)
....
Such pattern does work with runTest(standardTestDispatcher)
Jay
08/23/2025, 9:49 PMMario Andhika
08/28/2025, 2:37 AMJay
08/28/2025, 6:02 AMalbrechtroehm
08/28/2025, 9:12 AMtestApplication
?Dewan Tawsif
08/28/2025, 12:58 PMCacheControl.FORCE_CACHE
to achieve this behavior.