deepset-ai/haystack · error · TypeError

The parameter 'http_client_kwargs' must be a dictionary.

Error message

The parameter 'http_client_kwargs' must be a dictionary.

What it means

TypeError raised by `init_http_client` when the http_client_kwargs parameter is truthy but not a dict. This helper builds an httpx (async) client and requires keyword arguments as a mapping so it can copy and post-process them (e.g. converting a 'limits' dict to httpx.Limits).

Source

Thrown at haystack/utils/http_client.py:35

) -> httpx.AsyncClient | None: ...
def init_http_client(
    http_client_kwargs: dict[str, Any] | None = None, async_client: bool = False
) -> httpx.Client | httpx.AsyncClient | None:
    """
    Initialize an httpx client based on the http_client_kwargs.

    :param http_client_kwargs:
        The kwargs to pass to the httpx client.
    :param async_client:
        Whether to initialize an async client.

    :returns:
        A httpx client or an async httpx client.
    """
    if not http_client_kwargs:
        return None
    if not isinstance(http_client_kwargs, dict):
        raise TypeError("The parameter 'http_client_kwargs' must be a dictionary.")

    # Create a copy to avoid modifying the original dict
    processed_kwargs = http_client_kwargs.copy()

    # Handle limits parameter - convert dict to httpx.Limits object if needed
    if "limits" in processed_kwargs and isinstance(processed_kwargs["limits"], dict):
        limits_dict = processed_kwargs["limits"]
        processed_kwargs["limits"] = httpx.Limits(**limits_dict)

    if async_client:
        return httpx.AsyncClient(**processed_kwargs)
    return httpx.Client(**processed_kwargs)

View on GitHub (pinned to e318778c9b)

Solutions

  1. Pass http_client_kwargs as a dict, e.g. {'timeout': 10} or {'limits': {'max_connections': 10}}
  2. If you already have an httpx.Limits object, pass it inside the dict: {'limits': my_limits}
  3. Falsiness is allowed: pass None or {} to skip client creation entirely

Example fix

// before
client = init_http_client(http_client_kwargs=httpx.Limits(max_connections=5))
// after
client = init_http_client(http_client_kwargs={"limits": {"max_connections": 5}})
Defensive patterns

Strategy: type-guard

Validate before calling

def validate_client_kwargs(kwargs):
    if kwargs is not None and not isinstance(kwargs, dict):
        raise TypeError("http_client_kwargs must be a dict or None")

Type guard

def is_valid_http_client_kwargs(v) -> bool:
    return v is None or isinstance(v, dict)

Try / catch

try:
    client = init_http_client(http_client_kwargs=kwargs)
except TypeError as e:
    log.warning("Bad http_client_kwargs: %s; using defaults", e)
    client = None

Prevention

When it happens

Trigger: Passing http_client_kwargs as a string, list, object (e.g. an httpx.Limits instance directly), or dataclass instead of a dict to components/utils that call init_http_client, e.g. http_client_kwargs="timeout=5" or http_client_kwargs=httpx.Limits(...).

Common situations: Misreading the API and passing an httpx.Limits or httpx.Timeout object directly; passing JSON-serialized config strings; wiring a component's kwargs attribute to the wrong type.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/8296fa3372be9efa. Report an issue: GitHub.