How do you set timeouts in OkHttp correctly?

You set OkHttp timeout settings on the client builder, and there are four of them: a connect timeout, a read timeout, a write timeout, and an overall call timeout. The first three default to 10 seconds each, while the call timeout has no limit until you give it one. Setting them correctly is mostly a matter of knowing which stage of a request each one guards.

Developers usually meet these settings only after something has gone wrong. An upload fails at the same percentage every time, a request works on office Wi-Fi but stalls on a mobile network, or a call that should take two seconds hangs for half a minute. In most of these cases the timeout that fired was simply the wrong tool for the job, or it still had its default value.

This article walks through each timeout in turn: what it measures, what its failure looks like, and how to choose a value that suits your app. With a sensibly configured OkHttp client, timeout errors stop being mysteries and start being useful diagnostic information.

Four Timeouts, Four Different Jobs

A single HTTP call moves through distinct stages. The client opens a connection to the server, writes the request, waits, and reads the response. OkHttp timeout settings map onto those stages instead of applying one blunt limit to the whole exchange. The connect timeout bounds connection setup, the write timeout bounds sending the request body, the read timeout bounds waiting for response data, and the call timeout bounds absolutely everything from start to finish.

Because they guard different stages, the four values do not need to match. A chatty API client might connect quickly but wait a long time for one slow report endpoint. An upload feature might connect instantly yet need a generous write timeout on a weak uplink. Treating the settings independently is the whole point of having four of them.

val client = OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(30, TimeUnit.SECONDS)
    .callTimeout(45, TimeUnit.SECONDS)
    .build()

The Connect Timeout: Reaching the Server

The connect timeout starts ticking when OkHttp begins opening a connection and stops when that connection is ready to use. The window covers establishing the TCP connection and, for HTTPS calls, completing the TLS handshake, because an encrypted connection is not usable until both steps have finished.

If the server is unreachable, a firewall silently drops the packets, or the address simply never answers, this is the timeout that fires. The failure typically surfaces as a SocketTimeoutException whose message reports failing to connect after the configured number of milliseconds. It says nothing about your request itself, because the request was never sent.

Short connect timeouts suit most apps. A server that cannot be reached within a few seconds is unlikely to become reachable just by waiting longer, and failing fast lets recovery logic try another route or address. Values beyond 10 to 15 seconds rarely help real users. One caveat: the connect timeout does not strictly control how long resolving the host name takes, so a very slow name lookup can still add delay before this clock even starts.

The Read Timeout: Waiting for the Server to Answer

The read timeout governs how long OkHttp waits for data to arrive while reading a response. It starts to matter once the request has been sent: a server that needs time to run a query, assemble a report, or call its own services consumes read timeout while it thinks, before the first response byte comes back.

The subtlety most developers miss is that the read timeout measures gaps, not totals. Every chunk of data that arrives restarts the wait, so a download that keeps streaming can legitimately run for many minutes under a 10-second read timeout. What this timeout actually catches is a server that goes quiet: connected, but sending nothing.

That behaviour explains two common puzzles. A request that fails at almost exactly 10 seconds has usually hit the default read timeout against a slow endpoint. And a long-polling or streaming endpoint needs a deliberately raised read timeout, because holding a response open is its whole design. If you need a hard limit on total duration instead, that is the call timeout’s job.

The Write Timeout: Sending Data the Other Way

The write timeout is the read timeout’s mirror image: it limits how long OkHttp will spend pushing the request body to the server when the other side stops accepting data. On fast networks it almost never fires, because the body leaves the device quickly. On a congested mobile uplink carrying a large upload, the network and the server together decide how fast bytes drain, and the write timeout is what stops the call from stalling forever.

Like the read timeout, it watches for stalls rather than total time, so a steady but slow upload can continue well beyond the configured value as long as data keeps moving. If your uploads die partway through on poor connections but sail through on Wi-Fi, the write timeout is the first setting to inspect. Raising it moderately, and pairing it with a call timeout that reflects how long a user should reasonably wait, usually resolves the problem without masking genuinely dead connections.

The Call Timeout: A Ceiling for the Whole Call

The call timeout is the only setting that covers a call end to end. Its clock starts when the call begins and keeps running through connection setup, any redirects or retries, writing the request, and reading the full response body. When it expires, the call is cancelled wherever it happens to be.

Unlike the other three, the call timeout has no default. Unless you set one, a call can in theory run indefinitely, as long as no individual stage stalls long enough to trip its own timeout. A server that drips one byte every few seconds can hold a request open for hours without ever violating a 10-second read timeout, which is exactly the loophole the call timeout closes.

Think of the call timeout as the deadline your user experiences. If a screen should never wait more than 30 seconds for its data, a 30-second call timeout expresses that directly, and the stage-specific timeouts can stay at values tuned to the network rather than to the interface.

What a Timeout Failure Looks Like in Your Code

All four timeouts report themselves the same way at the surface. A synchronous call throws, and an asynchronous call delivers the failure to its callback. The exception is a SocketTimeoutException, which is a type of IOException, so error handling written for ordinary network failures catches it without special cases.

The message and the timing tell you which timeout fired. A failure to connect within the configured window points at the connect timeout, while a failure that arrives after a call has run for exactly your call timeout value means the overall deadline expired. Logging the exception message alongside the request makes production bug reports far easier to act on.

Notice what a timeout is not: an HTTP error. A 404 or 500 response means the exchange completed successfully at the network level, and no timeout was involved at all. Keeping those categories separate, in your logs and in your thinking, prevents hours of debugging the wrong layer.

One Client, With Room for Exceptions

Timeouts are properties of the client, not of individual requests, so every call made with a client shares its configuration. That is one more reason to build a single, well-configured OkHttpClient and reuse it everywhere: the OkHttp timeout settings you tuned apply consistently, and the client can pool connections efficiently behind the scenes.

Real apps still meet endpoints with unusual needs. A legacy reporting endpoint might legitimately need 90 seconds while everything else should fail within 10. For those cases, derive a second client from the first with newBuilder() and override just the timeouts. The derived client shares the connection pool and dispatcher of the original, so it is cheap to create. Recent versions also let you adjust the timeout attached to an individual call before executing it, which suits one-off exceptions.

What you should not do is build a brand-new client for every request merely to change a timeout. That throws away connection pooling, multiplies threads and sockets, and turns a simple configuration question into a performance problem.

Ping Interval: Policing Long-Lived Connections

One related setting deserves a mention: pingInterval. HTTP/2 connections are designed to stay open and carry many requests, which creates a failure mode the classic timeouts handle badly — a connection that looks open but is silently dead, as happens when a phone moves between networks or a carrier drops the session.

With a ping interval set, OkHttp periodically sends a ping frame on each HTTP/2 connection. If the other side does not answer in time, the connection is closed and its calls fail, so fresh connections get established instead of requests vanishing into a dead socket. The same mechanism helps keep WebSocket connections honest. Ping interval is off by default, and it is a liveness check rather than a request timeout, so choose it based on how quickly dead connections must be detected, not on how long requests take.

Timeout Mistakes That Cause Production Bugs

A handful of configuration errors account for most timeout trouble. The first is setting a timeout to zero hoping for speed: zero disables the timeout entirely, so a stalled call can wait forever and quietly consume threads and connections. The second is the opposite — setting every value to several minutes “to be safe”, which turns genuine failures into an app that appears frozen.

The third is confusing the read timeout with a total limit, then wondering why downloads outlast it. The fourth is raising timeouts to compensate for a slow server, which hides the real problem while users still wait. Finally, remember that timeouts only bound the waiting: what happens after a failure matters just as much, so it is worth understanding how OkHttp recovers from failed connections before you finalise your configuration.

Frequently Asked Questions

What happens if I set an OkHttp timeout to zero?

Zero means no timeout at all for the connect, read and write settings, and no overall limit for the call timeout. The call will wait indefinitely for that stage to complete. That is occasionally what a controlled internal tool wants, but in a user-facing app it usually ends with stuck calls piling up, so an explicit generous value is almost always better than zero.

Why does my request fail after almost exactly ten seconds?

Ten seconds is the default for the connect, read and write timeouts, so a failure at that mark means one of them fired. The exception message separates the cases: a failure to connect points at reaching the server, while a timeout after the request was sent means the server produced no data in time. The fix is to raise the specific timeout that fired, not all of them.

Why can a download run for minutes under a 10-second read timeout?

Because the read timeout limits the pause between chunks of incoming data, not the length of the transfer. As long as the server keeps sending, the call continues. If you need the transfer itself capped, add a call timeout, which measures the whole call from start to finish and cancels it when the deadline passes.

Can I give one slow endpoint a longer timeout than the rest?

Yes. Build your normal client once, then derive a variant with newBuilder() that overrides the timeouts for that endpoint; the two clients share their connection pool and dispatcher, so the variant costs almost nothing. Newer versions also allow adjusting the timeout on an individual call before it runs, which is handy for a single exceptional request.

Conclusion

OkHttp timeout settings stop being confusing once each one is tied to the stage it guards. The connect timeout covers reaching the server, the read and write timeouts cover stalls while data moves in either direction, and the call timeout sets the overall deadline your users actually experience.

Start from the defaults, watch which timeout fires when something goes wrong, and adjust that one value for a clear reason. A client configured that way fails quickly when the network is truly broken, waits patiently when a server is merely slow, and gives you error messages that point at the real problem.

1 thought on “How do you set timeouts in OkHttp correctly?”

  1. Pingback: How does OkHttp recover from failed connections? - OkHttp

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top