Skip to content

[Bug]: Discord gateway fails to connect through SOCKS proxy -- missing proxy support #6649

@Microstronggo

Description

@Microstronggo

Bug Description

The Discord gateway adapter (gateway/platforms/discord.py) has no proxy support. In network environments where Discord is restricted (e.g., mainland China), the gateway cannot connect to Discord or send messages, even when a local SOCKS proxy (Shadowrocket, Clash, etc.) is running and working.

The bot fails to connect at startup, and if connection somehow succeeds, sending messages also fails with the same error.

Steps to Reproduce

  1. Set up Hermes Gateway with Discord enabled and a valid bot token
  2. Run on a network where discord.com is restricted at the TCP level (e.g., mainland China, GFW blocks TLS handshake to Discord)
  3. Start a local SOCKS5 proxy (e.g., Shadowrocket on 127.0.0.1:1082) that can reach Discord
  4. Set proxy env vars or rely on auto-detection: ALL_PROXY=socks5://127.0.0.1:1082
  5. Run hermes gateway run
  6. Discord fails to connect with timeout

Expected Behavior

Discord adapter should detect and use the available SOCKS proxy to connect to Discord, similar to how the Telegram adapter already supports proxy configuration via _resolve_proxy_url() in gateway/platforms/telegram_network.py.

Actual Behavior

[Discord] Timeout waiting for connection to Discord

Or if connection partially succeeds, sending messages fails:

[Discord] Failed to send Discord message: General SOCKS server failure

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

Discord

Operating System

macOS 15.2

Python Version

3.11.12

Hermes Version

0.8.0

Relevant Logs / Traceback

Root Cause Analysis (optional)

1. No proxy configuration passed to discord.py

The DiscordAdapter.connect() method creates the bot without any proxy configuration:

self._client = commands.Bot(
    command_prefix="!",
    intents=intents,
)

discord.py uses aiohttp internally, which does not read standard proxy environment variables (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY). The commands.Bot() constructor accepts a connector kwarg (passed through to discord.Client.__init__), but it is never set by the adapter.

For comparison, the Telegram adapter (gateway/platforms/telegram_network.py) already has _resolve_proxy_url() and properly configures proxy support.

2. Critical: aiohttp_socks.ProxyConnector requires rdns=True

When injecting a SOCKS connector, the rdns parameter must be explicitly set to True. With the default rdns=None, Shadowrocket (and likely Clash and similar proxies) rejects the connection with SOCKS5 error code 1: "General SOCKS server failure".

# FAILS -- rdns defaults to None
ProxyConnector.from_url('socks5://127.0.0.1:1082')
# -> ProxyError: General SOCKS server failure

# WORKS -- rdns explicitly set to True
ProxyConnector(host='127.0.0.1', port=1082, proxy_type=ProxyType.SOCKS5, rdns=True)
# -> Connection successful

rdns=True forces DNS resolution through the proxy (remote DNS), which is required by many SOCKS proxy implementations and essential for bypassing DNS pollution.

Proposed Fix (optional)

Add proxy auto-detection and connector injection in gateway/platforms/discord.py before commands.Bot() creation:

# Resolve proxy for Discord connection
_discord_proxy = (
    os.getenv("DISCORD_PROXY", "") or
    os.getenv("ALL_PROXY", "") or
    os.getenv("all_proxy", "") or
    os.getenv("HTTPS_PROXY", "") or
    os.getenv("https_proxy", "")
)
if not _discord_proxy:
    # Auto-detect common local SOCKS proxy (Shadowrocket, Clash, etc.)
    import socket
    for _pp in [1080, 1082, 7890, 7891]:
        _s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            _s.settimeout(0.3)
            _s.connect(("127.0.0.1", _pp))
            _discord_proxy = f"socks5://127.0.0.1:{_pp}"
            break
        except (OSError, ConnectionRefusedError):
            pass
        finally:
            _s.close()

_bot_kwargs = {}
if _discord_proxy and _discord_proxy.startswith("socks"):
    try:
        from aiohttp_socks import ProxyConnector
        from python_socks import ProxyType, parse_proxy_url
        _ptype, _phost, _pport, _puser, _ppass = parse_proxy_url(_discord_proxy)
        # rdns=True is critical: resolves DNS through the proxy,
        # required for Shadowrocket and many SOCKS implementations
        _connector = ProxyConnector(
            host=_phost, port=_pport, proxy_type=_ptype,
            username=_puser, password=_ppass, rdns=True,
        )
        _bot_kwargs["connector"] = _connector
        logger.info("[%s] Using SOCKS proxy for Discord: %s (rdns=True)", self.name, _discord_proxy)
    except ImportError:
        logger.warning("[%s] aiohttp_socks not installed, proxy won't work. Run: pip install aiohttp-socks", self.name)

# Create bot
self._client = commands.Bot(
    command_prefix="!",
    intents=intents,
    **_bot_kwargs,
)

After applying the fix:

[Discord] Using SOCKS proxy for Discord: socks5://127.0.0.1:1082 (rdns=True)
[Discord] Connected as hermes_bot#1415
[Discord] Synced 100 slash command(s)
✓ discord connected

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions