-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
SOCKS5 proxy authentication failure raises ProxyError instead of NetworkError #28062
Copy link
Copy link
Closed
Labels
Description
Operating System
Ubuntu 24.04 (Docker)
Programming Language
Python
CCXT Version
4.5.32
Description
When using a SOCKS5 proxy with authentication, a temporary proxy authentication failure raises:
python_socks._errors.ProxyError: Username and password authentication failure
This exception propagates through CCXT without being mapped to the CCXT error hierarchy (such as NetworkError or OperationFailed).
Because of this, applications using CCXT (for example Freqtrade) treat the error as fatal instead of a transient network issue.
This makes it impossible to retry automatically when the proxy provider temporarily fails authentication.
Expected behavior
SOCKS proxy connection failures should be mapped to a CCXT network-related exception, for example:
- NetworkError
- OperationFailed
so that callers can handle retries properly.
Actual behavior
The raw exception propagates:
File "/freqtrade/freqtrade/resolvers/exchange_resolver.py", line 44, in load_exchange
exchange = ExchangeResolver._load_exchange(
exchange_name,
...<5 lines>...
},
)
File "/freqtrade/freqtrade/resolvers/exchange_resolver.py", line 77, in _load_exchange
exchange = ex_class(**kwargs)
File "/freqtrade/freqtrade/exchange/binance.py", line 81, in __init__
super().__init__(*args, **kwargs)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/freqtrade/freqtrade/exchange/exchange.py", line 299, in __init__
self.reload_markets(True, load_leverage_tiers=False)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/freqtrade/freqtrade/exchange/exchange.py", line 709, in reload_markets
retrier(self._load_async_markets, retries=retries)(reload=True)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "/freqtrade/freqtrade/exchange/common.py", line 179, in wrapper
return f(*args, **kwargs)
File "/freqtrade/freqtrade/exchange/exchange.py", line 682, in _load_async_markets
markets = self.loop.run_until_complete(self._api_reload_markets(reload=reload))
File "/usr/local/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete
return future.result()
~~~~~~~~~~~~~^^
File "/freqtrade/freqtrade/exchange/exchange.py", line 669, in _api_reload_markets
await self._api_async.load_markets(reload=reload, params={})
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/base/exchange.py", line 341, in load_markets
raise e
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/base/exchange.py", line 333, in load_markets
result = await self.markets_loading
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/base/exchange.py", line 300, in load_markets_helper
markets = await self.fetch_markets(params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/binance.py", line 3130, in fetch_markets
results = await asyncio.gather(*promisesRaw)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/binance.py", line 11587, in request
response = await self.fetch2(path, api, method, params, headers, body, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/base/exchange.py", line 990, in fetch2
raise e
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/base/exchange.py", line 978, in fetch2
return await self.fetch(request['url'], request['method'], request['headers'], request['body'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/ccxt/async_support/base/exchange.py", line 217, in fetch
async with session_method(yarl.URL(url, encoded=True),
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
data=encoded_body,
^^^^^^^^^^^^^^^^^^
headers=request_headers,
^^^^^^^^^^^^^^^^^^^^^^^^
timeout=(self.timeout / 1000),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
proxy=final_proxy) as response:
^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp/client.py", line 1510, in __aenter__
self._resp: _RetType = await self._coro
^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp/client.py", line 779, in _request
resp = await handler(req)
^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp/client.py", line 734, in _connect_and_send_request
conn = await self._connector.connect(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
req, traces=traces, timeout=real_timeout
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp/connector.py", line 672, in connect
proto = await self._create_connection(req, traces, timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp/connector.py", line 1239, in _create_connection
_, proto = await self._create_direct_connection(req, traces, timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp/connector.py", line 1580, in _create_direct_connection
transp, proto = await self._wrap_create_connection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<7 lines>...
)
^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp_socks/connector.py", line 66, in _wrap_create_connection
return await self._connect_via_proxy(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<4 lines>...
)
^
File "/home/ftuser/.local/lib/python3.13/site-packages/aiohttp_socks/connector.py", line 123, in _connect_via_proxy
stream = await proxy.connect(
^^^^^^^^^^^^^^^^^^^^
...<4 lines>...
)
^
File "/home/ftuser/.local/lib/python3.13/site-packages/python_socks/async_/asyncio/v2/_proxy.py", line 79, in connect
return await self._connect(
^^^^^^^^^^^^^^^^^^^^
...<4 lines>...
)
^
File "/home/ftuser/.local/lib/python3.13/site-packages/python_socks/async_/asyncio/v2/_proxy.py", line 143, in _connect
raise ProxyError(e, error_code=e.error_code)
python_socks._errors.ProxyError: Username and password authentication failure
Minimal reproducible example
import ccxt.async_support as ccxt
import asyncio
async def test():
exchange = ccxt.binance({
"enableRateLimit": True,
"socksProxy": "socks5://user:pass@proxy:1080",
})
exchange.verbose = True
await exchange.load_markets()
asyncio.run(test())Reactions are currently unavailable