{"id":"28c4027f14724dc0","repo":"encode/httpx","slug":"cannot-reopen-a-client-instance-once-it-has-been","errorCode":null,"errorMessage":"Cannot reopen a client instance, once it has been closed.","messagePattern":"Cannot reopen a client instance, once it has been closed\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"httpx/_client.py","lineNumber":1283,"sourceCode":"        Close transport and proxies.\n        \"\"\"\n        if self._state != ClientState.CLOSED:\n            self._state = ClientState.CLOSED\n\n            self._transport.close()\n            for transport in self._mounts.values():\n                if transport is not None:\n                    transport.close()\n\n    def __enter__(self: T) -> T:\n        if self._state != ClientState.UNOPENED:\n            msg = {\n                ClientState.OPENED: \"Cannot open a client instance more than once.\",\n                ClientState.CLOSED: (\n                    \"Cannot reopen a client instance, once it has been closed.\"\n                ),\n            }[self._state]\n            raise RuntimeError(msg)\n\n        self._state = ClientState.OPENED\n\n        self._transport.__enter__()\n        for transport in self._mounts.values():\n            if transport is not None:\n                transport.__enter__()\n        return self\n\n    def __exit__(\n        self,\n        exc_type: type[BaseException] | None = None,\n        exc_value: BaseException | None = None,\n        traceback: TracebackType | None = None,\n    ) -> None:\n        self._state = ClientState.CLOSED\n\n        self._transport.__exit__(exc_type, exc_value, traceback)","sourceCodeStart":1265,"sourceCodeEnd":1301,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_client.py#L1265-L1301","documentation":"Raised as RuntimeError by sync Client.__enter__ when self._state == ClientState.CLOSED. After __exit__/close() the client is permanently closed and cannot be reopened.","triggerScenarios":"Re-entering a 'with client:' block after the previous one exited, or calling client.__enter__() after client.close().","commonSituations":"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.","solutions":["Construct a new httpx.Client for each fresh usage scope.","Keep one long-lived client and use it without repeatedly entering/exiting context managers."],"exampleFix":"// before\nwith client:\n    client.get(url)\nwith client:  # RuntimeError: cannot reopen\n    client.get(url)\n// after\nwith httpx.Client() as client:\n    client.get(url)","handlingStrategy":"validation","validationCode":"import httpx\nif client.is_closed:\n    raise RuntimeError(\"client already closed; create a new httpx.Client\")\nwith client:\n    client.get(url)","typeGuard":"import httpx\n\ndef is_reusable(client: httpx.Client) -> bool:\n    return not client.is_closed","tryCatchPattern":"try:\n    with client:\n        client.get(url)\nexcept RuntimeError as exc:\n    if \"once it has been closed\" in str(exc):\n        with httpx.Client(...) as client:\n            client.get(url)\n    else:\n        raise","preventionTips":["Treat a closed client as disposable; always create a new one.","Avoid reusing a client across separate with-blocks.","Check client.is_closed before attempting to reopen."],"tags":["lifecycle","context-manager","sync"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}