The timeouts supported are:

  • :connect_timeout
  • :write_timeout
  • :read_timeout
  • :request_timeout
  • :operation_timeout
  • :keep_alive_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 raise a HTTPX::ConnectionTimeoutError exception, which subclasses HTTPX::TimeoutError.

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

:write_timeout (Default: 60)

The :write_timeout covers the total time it takes to fully send an HTTP request to the server.

Timeout expires raise a HTTPX::WriteTimeoutError exception.

:read_timeout (Default: 60)

The :read_timeout covers the total time it takes to fully read an HTTP response from the server.

Timeout expires raise a HTTPX::ReadTimeoutError exception.

(Note: the :stream plugin removes this default, in order to support endless responses.)

:request_timeout (no default)

The :request_timeout covers the total time it takes to send an HTTP request and read its response fromm the server.

You can use it to combine the 2 timeouts above into 1, and don’t care that much about knowing whether the request failed on writing or reading.

Timeout expires raise a HTTPX::RequestTimeoutError exception.

:operation_timeout (no default)

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

Contrary to the timeouts above, which are deadline oriented, :operation_timeout is used for the individual socket operations, so overall request/response turnaround time may still be quite high, given slow servers can still take advantage of it. If this is important to you, consider using :read_timeout or :write_timeout instead.

Timeout expires raise a HTTPX::TimeoutError exception.

(Note: the :stream plugin sets this timeout to 60 seconds.)

:keep_alive_timeout (Default: 20)

The :keep_alive_timeout is the time after last use of a connection (if the connection is persistent) that httpx will consider it to be reused for subsequent requests . This timeout is reset after every new request on that connection. 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.


Why are read/write timeouts deadline oriented, instead of socket op timeouts, like in most other HTTP client libraries?

Most other libraries only support HTTP/1.1 , which means there’s a direct mapping between the TCP operation to the HTTP interaction (i.e. a read timeout implies one failed reading the HTTP response). This is not true anymore with HTTP/2, where successive socket reads/writes happen during a single HTTP interaction. This leads to confusion, hence why it was replaced by a single op timeout, :operation_timeout, applicable to both socket reads and writes.

:write_timeout, :read_timeout and :request_timeout are deadline-oriented, in that they meter the time waiting to flush the request to the server, or fully getting a response, or both. This fits the purpose of an HTTP client better, as one doesn’t need to know about which socket, if any, is being used, and it is also less exposed to slow servers of the “dripping” kind.

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