The timeouts supported are:

  • :connect_timeout
  • :operation_timeout
  • :keep_alive_timeout
  • :total_timeout

The can be passed as an extra option to the session:

HTTPX.with(timeout: { operation_timeout: 15 }).get("https://google.....")

Timeouts which expire will trigger an error of the HTTPX::TimeoutError type.

:connect_timeout (Default: 60)

The :connect_timeout covers the time it takes to establish a TCP connection, and in case it’s a TLS connection, the time it takes to establish a TLS connection.

Timeout expires trigger a HTTPX::ConnectionTimeoutError exception, which subclasses HTTPX::TimeoutError.

Note: This timeout does not cover the time it takes to perform the DNS hostname resolution.

:operation_timeout (Default: 60)

The :operation_timeout is used when waiting for read/write interests on the TCP connection.

:keep_alive_timeout (Default: 20)

The :keep_alive_timeout is the time after last use of connection (if the connection is persistent) that we will reuse the it for subsequent requests for the same origin. This timeout is therefore reset after every successful response. If the timeout expires when sending a request for the same origin, one of two things will happen:

  • HTTP/2: a PING frame will be sent on the connection to check availability of the connection; if still available, it will be reused, otherwise a new connection will be opened.
  • HTTP/1: a new connection will be opened.


The :total_timeout covers the time to use connections from the moment connection starts, i.e. it cover the time for all requests to be processed. If connnections are still available beyond :total_timeout, a HTTPX::TotalTimeoutError exception is raised.


Why are there no read/write timeouts?

Due to the nature of how concurrent requests are managed, one can’t specify operation timeouts as granularly. Instead, all of those are replaced by a single operation timeout, which acts upon the whole batch: if none of the requests has data to process (send to / receive from), it will return an Error Response with a Timeout error, for the incomplete ones.

What about DNS timeouts?

Resolver options are passed as :resolver_options, as a hash. The right answer depends of which resolver you’re using:

System resolver

You can pass a :timeouts to the :resolver_options hash, which is documented in the ruby documentation.

Native resolver

As the native resolver reuses the same system resolver options API, the suggestion above still stands.

HTTP resolver (DoH)

As the DNS connection is an HTTP(S) connection, all of the above timeouts are to be reused.

Next: Connections