Releases: ktorio/ktor
Releases · ktorio/ktor
3.4.0
Published 22 January 2026
Features
- KTOR-8316 Support OpenAPI specification for the Ktor Client and Server Application
- KTOR-9085 Read OpenAPI security details from authentication plugin
- KTOR-8993 Use runtime-generated spec for OpenAPI / Swagger plugins
- KTOR-9086 Read OpenAPI default content type information from ContentNegotiation plugin
- KTOR-8859 Routing documentation compiler plugin
- KTOR-8936 Routing documentation runtime API
- KTOR-9087 Generate JSON schema for type references when using Jackson and Gson
- KTOR-7075 Zstd support
- KTOR-9209 Support Jackson 3
- KTOR-9198 Auth/Bearer: Make BearerAuthProvider detect disguised Bearer scheme
- KTOR-8927 Support for
respondResource - KTOR-9162 Auth API key plugin
- KTOR-7882 Support HTTP QUERY method
- KTOR-8195 Partial HTML response
- KTOR-8985 EngineMain: Support reading trust store settings from the configuration
- KTOR-9066 Add duplex streaming for OkHttpClient
- KTOR-8180 Auth: Provide control over tokens to user code
- KTOR-8273 iOS native interop for WebRTC client
- KTOR-8956 DI: Allow file configuration
- KTOR-9157 Support SIGINT on web and SIGTERM on Native
Improvements
- KTOR-8890 Rename target jsAndWasmShared to web
- KTOR-9242 Upgrade to Kotlin 2.3
- KTOR-9243 Update libcurl to 8.18.0
- KTOR-9014 Deprecate DarwinLegacy engine
- KTOR-8931 Test iOS target of the WebRTC Client in Ktor-Chat
- KTOR-9199 Make HttpHeaders strings const
- KTOR-9208 Expose plusIsSpace in parseUrlEncodedParameters
- KTOR-2404 Ktor Oauth2 feature sends 401 response when the client secret is invalid
- KTOR-9097 Java: Use HTTP/2 by default
- KTOR-8740 HTMX: Missing DSL for some attributes
- KTOR-9171 Redesign ByteReadChannel.readUTF8Line API
- KTOR-4219 Make readUTF8LineTo return number of read symbols instead of boolean
- KTOR-6761 Apache5: Simplify configuration of ConnectionManager
- KTOR-9037 Multipart/form-data: Make
formData's block inline - KTOR-9126 Missing function ByteReadChannel.readTo(sink: RawSink, byteCount: Long)
- KTOR-9026 Introduce/reuse interfaces for logging selectors
- KTOR-6766 Deprecate Apache 4 engine
- KTOR-8642 Excessive memory allocations while writing bytes into write channel of TCP/IP socket
- KTOR-9137 ByteReadChannel.readUTF8Line is inefficient for long lines
- KTOR-8657 Remove kotlinx-datetime from ktor-server-default-headers dependencies
- KTOR-8941 Add override DI conflict policy
Bugfixes
- KTOR-9258 headers { } block does not affect the request in
defaultRequestdue to function name collision with io.ktor.http.headers - KTOR-9235 HttpCookies: Support parsing non-compilant
Expiresdates of Set-Cookie header - KTOR-8945 ByteReadChannel.readUTF8Line doesn't throw TooLongLineException when the limit is reached
- KTOR-8339 Curl:
caPathis not set by default in the Curl client on linuxArm64 - KTOR-9188 WebRTC.
IceServer.urlsshould be a list. - KTOR-9148 Logging: Body logging of multipart/form-data requests hangs when OkHttp format is on
- KTOR-9166 CORS: Excessive logs on INFO level since 3.3.3
- KTOR-9130 Missing implementation of
getPluginIdmethod error with Kotlin 2.3.0-RC - KTOR-9147 OpenAPI: "AssertionError: Cannot add a performance measurements" leading to StackOverflowError within a multimodule project
- KTOR-2162 JettyKtorHandler executor will never grow beyond core size
- KTOR-9201
audio/x-matroskais wrongly recognized asmkvtype - KTOR-9146 Run HttpStatement.execute on the engine's dispatcher
- KTOR-6300 Native engines should use Dispatchers.IO not Dispatchers.Unconfined
- KTOR-9098 Curl: HttpResponse.version always returns HTTP_1_1
- KTOR-9100 Curl always uses HTTP/1.1
- KTOR-7162 DefaultRequest: Configuration applied twice for client created with
HttpClient.config - KTOR-9102 SSE: Java engine does not close the underlying connection when SSE session is canceled
- KTOR-9108 SSE: The handler adds
Connection: Keep-Aliveheader, which is incompatible with HTTP/2 - KTOR-7884 Auth: The MutableList cannot be accessed since 3.0.0
- KTOR-6569 Bearer auth: Don't cache client bearer token (option)
- KTOR-4946 Auth: Bearer authentication - unable to update tokens
- KTOR-4759 Auth: BearerAuthProvider caches result of loadToken until process death
- KTOR-9129 Fix SendCountExceedException when maxRetries = Int.MAX_VALUE
- KTOR-9113 Netty HTTP2 server hangs on the plugin exception
- KTOR-9135 buildOpenApi fails with unknown serializer
- KTOR-8285 Bearer Auth: request cancellation causes refresh token invalidation
- KTOR-5241 The decodeBase64Bytes method doesn't throw an exception on illegal base64 characters
- KTOR-8912 Incorrect KDoc of ApplicationConfig.tryGetStringList
- KTOR-9079 The ktor-server-test-host module, having
junit-jupiterruntime dependency, causes conflicts - KTOR-7713 HttpCallValidatorConfig.handleResponseException() should receive a CallExceptionHandler
- KTOR-7121 testApplication: Test HTTP client does not use specified coroutine dispatcher
- KTOR-8785 DI: JobCancellationException during cleanup
- KTOR-6198 Client/WebSocket/Darwin close code and reason are incorrect
- KTOR-7824 Ktor doesn't parse multiple headers
3.3.3
Published 26 November 2025
Improvements
- KTOR-6837 Discrepancies when parsing URL host with CIO and Darwin engines compared to the rest engines
- KTOR-9050 Logging: SimpleLogger should be an object, not a class
- KTOR-9094 Jetty Client: Support HTTP/2 over cleartext (h2c)
- KTOR-9120 OpenAPI gen: missing operationId for KDoc fields
- KTOR-3019 Improve logging for CORS plugin
Bugfixes
- KTOR-8671 Netty: RejectedExecutionException during shutdown on MacOS when dev mode is enabled
- KTOR-9096 Darwin: New SSE handlers stop responding after canceling few SSE sessions
- KTOR-9125 Double ResponseSent invocation when exception is thrown after respond
- KTOR-8878 OpenAPI: StackOverflowError when a response object has property with
@Contextualserializer - KTOR-8947 Java, ContentEncoding: IllegalHeaderNameException is thrown for ":status" pseudo header with HTTP/2
- KTOR-9092 NettyHttp2Handler throws IllegalArgumentException: 'ktor.ApplicationCall' is already in use
- KTOR-8924 Curl: Client sends both Transfer-Encoding and Content-Length headers for DELETE requests with body
- KTOR-8838 Exception handling issue in client cache
3.3.2
Published 5 November 2025
Improvements
- WebRTC Client. Remove redundant targets (KTOR-9062)
- Add Socks proxy support to Darwin engine (KTOR-8968)
- Java: Improve error message when SOCKS proxy is used (KTOR-2908)
Bugfixes
- HttpRequestRetry: SendCountExceedException when max retries is more than maxSendCount of HttpSend (KTOR-5850)
- Darwin: The
maxFrameSizeoption has no effect (KTOR-6963) - OpenAPI: StackOverflowError when a response object has property with
@Contextualserializer (KTOR-8878) - OpenAPI gen: missing KDoc fields (KTOR-9021)
- Server call.request.path() returns routing selectors in path (KTOR-7639)
- StaticContent doesn't allow siblings (KTOR-9012)
- HttpCache: FileStorage doesn't use given dispatcher for all file operations (KTOR-8832)
- Curl: SOCKS proxy doesn't work (KTOR-9008)
- Netty: java.lang.VerifyError is thrown on Android since 3.3.0 (KTOR-8916)
- Response body channel is canceled while the body is being saved when having HttpRequestRetry and onDownload (KTOR-8975)
- HttpCache: InvalidCacheStateException when varyKeys stored in files contain uppercase letters since 3.3.0 (KTOR-8970)
3.3.1
Published 8 October 2025
Improvements
Bugfixes
- NumberFormatException when Content-Length header value contains null bytes (KTOR-4828)
- SerializationException: Serializer for class 'ClientSSESession' is not found when server responds with JSON (KTOR-7631)
- Netty: loadConfiguration missing enableHttp2 and enableH2c properties (KTOR-8898)
- Netty: EmbeddedServer.stop always blocks for twice of shutdownGracePeriod (KTOR-8770)
- shutdownGracePeriod is used instead of shutdownTimeout in EmbeddedServer.stop() (KTOR-8771)
- Support serving static resources within bootJar (KTOR-8592)
3.3.0
Published 11 September 2025
Features
- Support for server side http2 without tls (h2c) (KTOR-4750)
- OpenAPI generation build extension preview (KTOR-8721)
- Serve static resources with caching headers and ETag based on sha256 of content (KTOR-6700)
- Jetty engine: Upgrade Jetty dependencies to the latest version 12 (KTOR-6734)
- Static content: Support a custom respond logic if the file is not found (KTOR-8496)
- Upgrade OkHttp to version 5.0.0 (KTOR-8652)
- WebRTC Client, Android + WASM (KTOR-7958)
Improvements
- SSE: Cannot read response body from SSEClientException (KTOR-8165)
- SSE: "SSEClientException: Content-Length mismatch" on saving response body in DefaultResponseValidation (KTOR-8753)
var Route.staticRootFolder: File?should be deprecated (KTOR-5836)- Add
image/bmpto the ContentType (KTOR-8735) - Add some missing image content types (KTOR-8624)
- Upgrade to Kotlin 2.2 (KTOR-8647)
- Bump Kotlin API level to 2.2 (KTOR-8637)
- CIO: The engine ignores system proxy settings (KTOR-5922)
Bugfixes
- Performance regression when using ContentEncoding and HttpRequestRetry since 3.2.0 (KTOR-8820)
- Big number of simultaneous outbound web socket connections leads to a coroutine deadlock (KTOR-8829)
- DI: JobCancellationException during cleanup (KTOR-8785)
- Autoreloading: JobCancellationException when app is reloaded in the debugger since 3.2.0 (KTOR-8810)
- HttpRedirect: The client is redirected when no Location header in response (KTOR-8697)
- SerializationException when Application.propertyOrNull() is called with type Map<String, Any?> (KTOR-8781)
- "Failed resolution of: Ljava/lang/management/ManagementFactory" on Android when JvmGcMetrics are initialized (KTOR-8714)
- HttpCache: all header values but first in HttpResponse.varyKeys() are ignored (KTOR-6402)
- HttpCache: plugin selects wrong cache entry when filtering Vary headers with different case (KTOR-7621)
- CountedByteWriteChannel: autoFlush of the source channel doesn't make the channel auto flushing (KTOR-8411)
3.2.3
3.2.2
Published 14 July 2025
Improvements
- SSE: Change the order of SSE field serialization: put
eventbeforedata(KTOR-8627)
Bugfixes
- CORS: server replies with the 405 status code on a preflight request when the plugin is installed in a route (KTOR-4499)
- Darwin: The Content-Encoding header is removed since 3.0.3 (KTOR-8526)
- JS/WASM: response doesn't contain the Content-Length header in a browser (KTOR-8377)
- StatusPages: response headers of OutgoingContent aren't available in the status handlers (KTOR-8232)
- testApplication: The
client.sse()acts like a REST call and not a stream in test environment (KTOR-7910) - Config deserialization - default properties problem (KTOR-8654)
- kotlinx.datetime is not available transitively in 3.2.1 (KTOR-8656)
- Request builder block overrides HTTP method in specific request builders (get, post, etc) (KTOR-8636)
3.2.1
Improvements
- Replace kotlinx.datetime APIs with kotlin.time (KTOR-8635)
- Thymeleaf: null values in template model (KTOR-8559)
- Publish Javadoc as a maven artifact (KTOR-3962)
- Netty: Invalid hex byte with malformed query string (KTOR-2934)
Bugfixes
- "Space characters in SimpleName" error when executing R8 mergeExtDex task with 3.2.0 (KTOR-8583)
- ForwardedHeaders: the plugin does not handle parameters case-insensitively (KTOR-8622)
- Potential race condition in
socket.awaitClosed(hangs indefinitely) since 3.2.0 (KTOR-8618) - Module parameter type Application.() -> kotlin.Unit is not supported in 3.2.0 (KTOR-8602)
- OkHttp: java.net.ProtocolException when sending MultiPartFormDataContent with onUpload (KTOR-6790)
- OAuth2 authentication provider breaks form-urlencoded POST requests when receiving request body (KTOR-4420)
- 404 for a link in KDoc for io.ktor.server.plugins.contentnegotiation.ContentNegotiation (KTOR-8597)
- Ktor fails to boot with default jvminline argument (KTOR-8608)
- Flow invariant is violated since 3.2.0 (KTOR-8606)
- ResponseSent hook handler of the plugin installed into a route isn't executed when an exception is thrown from the route (KTOR-6794)
3.2.0
Published 12 June 2025
Features
- Dependency injection Ktor extension (KTOR-8267)
- Support Version Catalog (KTOR-8162)
- Unix domain socket support at the Ktor Engine level (KTOR-4766)
- Allow suspend Ktor modules (KTOR-8005)
- Ability to use browser cookie storage (KTOR-539)
- Configuration file deserialization (KTOR-7874)
- HttpCache: Support evicting/clearing cache (KTOR-6653)
- File configuration for dependencies (KTOR-8304)
Improvements
- Excessive allocation of ApplicationConfig when loading multiple files from CLI (KTOR-8563)
- Linux curl engine doesn't work for simultaneous websocket and http request (KTOR-8259)
- ktor-network produces ProGuard warning (KTOR-8525)
- More overloads for StringValuesBuilder.appendAll (KTOR-8573)
- HttpClientCall: Deprecate
wrapWithContentandwrap(KTOR-8378) - Add a way to create an
ApplicationCallfor testing (KTOR-7607) - Configuration access API improvements (KTOR-8185)
- Application instance access in testApplication (KTOR-8215)
- The TestApplication client should be configurable and mutable (KTOR-8465)
- Support accessing resolved IP address on an instance of
io.ktor.network.sockets.InetSocketAddress(KTOR-8490) - Deprecate SaveBodyPlugin in favor of HttpClientCall.save (KTOR-8367)
- Obscure log message on server startup (KTOR-8519)
- Routing:
acceptshould return 406 if theAcceptheader isn't matched (KTOR-8416) - MicrometerMetrics: the
routelabel can exceed length limit (KTOR-7274) - Micrometer: Make route label configurable (KTOR-8183)
- Add more common ContentType values (KTOR-7108)
Bugfixes
- Logging/Darwin: IOException is thrown when detecting if body is a binary (KTOR-8581)
- Netty: NoSuchElementException or empty headers when responding with 204 (KTOR-8528)
- YAML configuration: NoSuchElementException when parameter is expanded with curly braces (KTOR-8575)
- ApplicationConfig: Most of the content is absent after merging configs (KTOR-8565)
- Android: "ProtocolException: TRACE does not support writing" when sending TRACE request (KTOR-8352)
- The "Content-Length: 0" header is added for GET requests sent to some servers (KTOR-6508)
- HttpRequestRetry: requests with some IOException's thrown by Java engine aren't retried (KTOR-6770)
- HttpCookies: Encoding of request cookies is not preserved in CookiesStorage (KTOR-8343)
- Url class mangles data URLs (KTOR-5708)
- SaveBodyPlugin: Logging plugin consumes response body (KTOR-6474)
- Config deserialization does not respect
testApplicationenvironment (KTOR-8436) - Resources: Exclude a parent from query params when it is an object (KTOR-8507)
- BearerAuthProvider does not clear token if refreshTokens returns null (KTOR-8470)
- Coroutines launched from RoutingContext are not cancelled upon server shutdown (KTOR-8338)
- Application job is not joined during shutdown (KTOR-8291)
- HttpCache: InvalidCacheStateException thrown when Vary header has different entries is overly severe (KTOR-8345)
- Fix socket channel close handling (KTOR-8201)
3.1.3
Published 5 May 2025
Improvements
- Implement toString for staticContentRoute (KTOR-8451)
- Don't send Authorization header for requests marked with markAsRefreshTokenRequest (KTOR-8107)
- ByteChannel single-byte operations are slow (KTOR-8412)
- Receiving multipart without Content-Length is very slow (KTOR-8407)
- MicrometerMetrics: different path 404s requests can be abused to trigger OOM (KTOR-8276)
- Compression & Static Content: No Vary Header when serving a compressed resource (KTOR-8326)
- HttpTimeout: Reference to nonexistent INFINITE_TIMEOUT_MS in the exception message (KTOR-8358)
Bugfixes
- Websockets: Unable to send a frame when ktor-serialization-kotlinx-json-jvm dependency is defined in Maven build (KTOR-7662)
- OkHttp: Cancelling of SSE request job doesn't cancel the connection (KTOR-8409)
- OkHttp: Exceptions are not propagated to flow collectors (KTOR-7947)
- OOM in CountedByteReadChannel while copying from multipart/form-data part channel (KTOR-8317)
- Apache5: "ProtocolException: OPTIONS request must have Content-Type header" is thrown when body isn't set (KTOR-8318)
- Netty/Websockets: server processes hanging in CLOSE_WAIT state after many concurrent requests (KTOR-7965)
- Update JTE to the version supporting Kotlin 2.1.0 (KTOR-8030)