Skip to content

SOCKS5 proxy authentication failure raises ProxyError instead of NetworkError #28062

@dima-dmytruk23

Description

@dima-dmytruk23

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())

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions