Ktor 3.4.1 Help

Response validation

By default, the Ktor HTTP client does not validate responses based on their HTTP status codes. If needed, you can enable and customize response validation using the following strategies:

Enable default validation

Ktor allows you to enable default validation by setting the expectSuccess property to true. When enabled, the client throws an exception for any response with a non-successful HTTP status code.

You can enable this behavior globally in the client configuration:

import io.ktor.client.* import io.ktor.client.engine.cio.* val client = HttpClient(CIO) { expectSuccess = true }

Alternatively, you can enable expectSuccess on a per-request basis. In this case, the following exceptions will be thrown for non-2xx error responses:

Custom validation

In addition to the default validation behavior, you can define custom response validation logic by using the HttpCallValidator plugin. This allows you to validate successful (2xx) responses or override how non-2xx responses are handled.

To install HttpCallValidator, call the HttpResponseValidator function inside a client configuration block:

val client = HttpClient(CIO) { HttpResponseValidator { // ... } }

Validate 2xx responses

Default validation throws exceptions only for non-2xx responses. If your application requires stricter validation, you can validate successful responses using the validateResponse {} function.

In the following example, the server returns a 2xx response containing an error payload in JSON format. The validateResponse {} block inspects the response body and throws a custom exception when an error is detected:

val client = HttpClient(CIO) { install(ContentNegotiation) { json() } HttpResponseValidator { validateResponse { response -> val error: Error = response.body() if (error.code != 0) { throw CustomResponseException(response, "Code: ${error.code}, message: ${error.message}") } } } }

Handle non-2xx exceptions

To customize how non-2xx response exceptions are handled, use the handleResponseExceptionWithRequest {} function.

In the following example, the client throws a custom MissingPageException for 404 Not Found responses instead of the default ClientRequestException:

class MissingPageException(response: HttpResponse, cachedResponseText: String) : ResponseException(response, cachedResponseText) { override val message: String = "Missing page: ${response.call.request.url}. " + "Status: ${response.status}." } fun main() { val client = HttpClient(CIO) { expectSuccess = true HttpResponseValidator { handleResponseExceptionWithRequest { exception, request -> val clientException = exception as? ClientRequestException ?: return@handleResponseExceptionWithRequest val exceptionResponse = clientException.response if (exceptionResponse.status == HttpStatusCode.NotFound) { val exceptionResponseText = exceptionResponse.bodyAsText() throw MissingPageException(exceptionResponse, exceptionResponseText) } } } } runBlocking { val httpResponse: HttpResponse = try { client.get("https://ktor.io/docs/missing-page.html") } catch (cause: ResponseException) { println(cause) cause.response } } }
09 February 2026