Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions py_clob_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
)
from .exceptions import PolyException
from .http_helpers.helpers import (
set_http_timeout,
add_query_trade_params,
add_query_open_orders_params,
delete,
Expand Down Expand Up @@ -124,6 +125,7 @@ def __init__(
funder: str = None,
builder_config: BuilderConfig = None,
tick_size_ttl: float = 300.0,
timeout: float = None,
):
"""
Initializes the clob client
Expand All @@ -143,6 +145,9 @@ def __init__(
self.creds = creds
self.mode = self._get_client_mode()

if timeout is not None:
set_http_timeout(timeout)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per-instance timeout parameter actually mutates global state

High Severity

The timeout parameter on ClobClient.__init__ suggests per-instance configuration, but set_http_timeout replaces a module-level global _http_client shared by all instances. Creating a second ClobClient with a different (or no) timeout silently overrides the first client's timeout. Ironically, this can reintroduce the exact duplicate-order problem the PR aims to fix — a user sets timeout=30 on one client, then another component instantiates a default client, resetting the timeout to httpx's default.

Additional Locations (1)
Fix in Cursor Fix in Web


if self.signer:
self.builder = OrderBuilder(
self.signer, sig_type=signature_type, funder=funder
Expand Down
12 changes: 10 additions & 2 deletions py_clob_client/http_helpers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@
_http_client = httpx.Client(http2=True)


def set_http_timeout(timeout: float) -> None:
"""
Reconfigure the module-level HTTP client with a custom timeout (in seconds).
"""
global _http_client
_http_client = httpx.Client(http2=True, timeout=timeout)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old HTTP client not closed, leaking connections

Medium Severity

set_http_timeout replaces the module-level _http_client with a new httpx.Client without calling .close() on the old one. Since the client is created with http2=True, the old instance holds open HTTP/2 connections and associated resources (sockets, TLS state) that are never properly released, causing a resource leak.

Fix in Cursor Fix in Web



def overloadHeaders(method: str, headers: dict) -> dict:
if headers is None:
headers = dict()
Expand Down Expand Up @@ -61,8 +69,8 @@ def request(endpoint: str, method: str, headers=None, data=None):
except ValueError:
return resp.text

except httpx.RequestError:
raise PolyApiException(error_msg="Request exception!")
except httpx.RequestError as exc:
raise PolyApiException(error_msg=f"Request exception: {exc}") from exc


def post(endpoint, headers=None, data=None):
Expand Down