encode/httpx · error · RuntimeError

Cannot reopen a client instance, once it has been closed.

Error message

Cannot reopen a client instance, once it has been closed.

What it means

Raised as RuntimeError by sync Client.__enter__ when self._state == ClientState.CLOSED. After __exit__/close() the client is permanently closed and cannot be reopened.

Source

Thrown at httpx/_client.py:1283

        Close transport and proxies.
        """
        if self._state != ClientState.CLOSED:
            self._state = ClientState.CLOSED

            self._transport.close()
            for transport in self._mounts.values():
                if transport is not None:
                    transport.close()

    def __enter__(self: T) -> T:
        if self._state != ClientState.UNOPENED:
            msg = {
                ClientState.OPENED: "Cannot open a client instance more than once.",
                ClientState.CLOSED: (
                    "Cannot reopen a client instance, once it has been closed."
                ),
            }[self._state]
            raise RuntimeError(msg)

        self._state = ClientState.OPENED

        self._transport.__enter__()
        for transport in self._mounts.values():
            if transport is not None:
                transport.__enter__()
        return self

    def __exit__(
        self,
        exc_type: type[BaseException] | None = None,
        exc_value: BaseException | None = None,
        traceback: TracebackType | None = None,
    ) -> None:
        self._state = ClientState.CLOSED

        self._transport.__exit__(exc_type, exc_value, traceback)

View on GitHub (pinned to b5addb64f0)

Solutions

  1. Construct a new httpx.Client for each fresh usage scope.
  2. Keep one long-lived client and use it without repeatedly entering/exiting context managers.

Example fix

// before
with client:
    client.get(url)
with client:  # RuntimeError: cannot reopen
    client.get(url)
// after
with httpx.Client() as client:
    client.get(url)
Defensive patterns

Strategy: validation

Validate before calling

import httpx
if client.is_closed:
    raise RuntimeError("client already closed; create a new httpx.Client")
with client:
    client.get(url)

Type guard

import httpx

def is_reusable(client: httpx.Client) -> bool:
    return not client.is_closed

Try / catch

try:
    with client:
        client.get(url)
except RuntimeError as exc:
    if "once it has been closed" in str(exc):
        with httpx.Client(...) as client:
            client.get(url)
    else:
        raise

Prevention

When it happens

Trigger: Re-entering a 'with client:' block after the previous one exited, or calling client.__enter__() after client.close().

Common situations: Storing a client and trying to reuse it as a context manager after it was already used and closed; retry logic that reopens a closed client.

Related errors


AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04). Data as JSON: /data/errors/28c4027f14724dc0.json. Report an issue: GitHub.