Understanding the Purpose of the timeout Parameter in httpx.AsyncClient

The timeout parameter in httpx.AsyncClient defines the maximum duration the client will wait for any phase of an HTTP request—connection establishment, data transmission, or response reception—before aborting and raising a TimeoutException.

The open-source tool holehe (by megadose) leverages httpx.AsyncClient to perform high-concurrency email reconnaissance across dozens of web services simultaneously. In holehe/core.py, the timeout value is injected directly into the client constructor to ensure that a single unresponsive service cannot stall the entire asynchronous batch operation.

How holehe Implements the timeout Parameter

Source Code Location

Within the repository's main entry point, the asynchronous HTTP client is instantiated with a user-supplied timeout value. The critical line appears in holehe/core.py at line 213:

client = httpx.AsyncClient(timeout=timeout)

This single argument propagates through every subsequent request made by the tool, establishing a hard ceiling on wait times for all network I/O.

Configuration via Command Line

Users control this value through the -T or --timeout CLI flag. The argument parser, located at lines 194–210 in holehe/core.py, defaults to 10 seconds if no override is provided:


# Simplified excerpt from core.py showing the argument definition

parser.add_argument(
    "-T", "--timeout",
    type=int,
    default=10,
    help="Timeout for each request (default: 10s)"
)

When the main execution loop begins, this integer is passed directly to the AsyncClient constructor, ensuring consistent behavior across all modules that consume the client instance.

Technical Breakdown of HTTPX Timeouts

When you pass a numeric value to timeout in httpx.AsyncClient, httpx internally constructs a Timeout configuration object that governs four distinct phases of the request lifecycle:

  • Connect: Time allowed to establish the TCP connection to the target host.
  • Write (Request): Time permitted to transmit the complete request body to the server.
  • Read (Response): Time to wait for the first byte of the response to arrive after the request is sent.
  • Total: The aggregate time limit for the entire transaction from connection to body download completion.

If any individual phase exceeds its allocated duration, httpx immediately raises a httpx.TimeoutException. This mechanism is essential for holehe's architecture, which uses asynchronous nurseries to launch many requests in parallel; without timeouts, a hung connection to one obscure service would backpressure the entire event loop, degrading performance for all other checks.

Practical Code Examples

Basic AsyncClient Usage with Timeout

The following pattern mirrors holehe's internal implementation, showing how to instantiate the client and handle timeout failures gracefully:

import httpx
import asyncio

async def probe_service(url: str, timeout_seconds: int = 10):
    client = httpx.AsyncClient(timeout=timeout_seconds)
    try:
        response = await client.get(url)
        return response.status_code == 200
    except httpx.TimeoutException:
        print(f"Request to {url} exceeded {timeout_seconds}s limit")
        return False
    finally:
        await client.aclose()

# Usage

asyncio.run(probe_service("https://example.com/api", timeout_seconds=5))

Adjusting Timeout in holehe CLI

When running holehe against slow-responding services, you can increase the threshold to accommodate network latency while still preventing indefinite hangs:


# Allow 20 seconds per request instead of the default 10

holehe -T 20 target@example.com

This command-line option maps directly to the timeout parameter discussed above, modifying the httpx.AsyncClient instantiation at core.py:213 before the scan begins.

Summary

  • The timeout parameter in httpx.AsyncClient sets hard limits on connection, write, read, and total request duration to prevent indefinite blocking.
  • In holehe, this parameter is exposed via the -T/--timeout flag (default 10s) and passed to the client constructor in core.py at line 213.
  • When any phase of the HTTP transaction exceeds the configured limit, httpx raises a TimeoutException, allowing the tool to skip unresponsive services and maintain high concurrency.
  • You can pass either a single float (applied to all phases) or a detailed httpx.Timeout object for granular control over specific stages of the request lifecycle.

Frequently Asked Questions

What happens when a request exceeds the timeout in httpx.AsyncClient?

When the configured duration is exceeded for any phase—connect, write, read, or total—httpx immediately raises a httpx.TimeoutException. In holehe, this exception is caught internally, marking the specific service check as failed while allowing the remaining concurrent probes to continue execution without interruption.

Can I set different timeouts for different network phases in holehe?

While holehe's CLI exposes only a single global timeout value, the underlying httpx.AsyncClient supports fine-grained control via the httpx.Timeout object. Advanced users modifying the source code in core.py can replace the integer timeout with a Timeout(connect=5.0, read=10.0, write=5.0, pool=5.0) configuration to assign distinct limits to each phase.

What is the default timeout value used by holehe?

According to the argument parser in holehe/core.py (lines 194–210), the default timeout is 10 seconds. This value is passed to httpx.AsyncClient(timeout=10) at line 213 unless the user overrides it with the -T flag.

Why is timeout critical for asynchronous batch processing tools like holehe?

Without a timeout parameter, a single unresponsive target server could keep a connection open indefinitely, consuming memory and file descriptors in the async event loop. By enforcing a strict timeout, holehe ensures that slow or dead services are quickly abandoned, preserving system resources and allowing the tool to complete scans of hundreds of services in seconds rather than hours.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →