XX-net/XX-Net · warning · XTunnelNotRunning

XTunnelNotRunning

Error message

XTunnelNotRunning

What it means

do_socks raises XTunnelNotRunning when the X-Tunnel proxy is unavailable. This first site fires when accessing g.x_tunnel.proxy_session fails or is unset — i.e. the X-Tunnel subsystem was never started or has already shut down, so attribute access on None raises and the except converts it to XTunnelNotRunning, letting try_loop fall back to another route.

Source

Thrown at code/default/smart_router/local/smart_route.py:249

    xlog.debug("host:%s:%d redirect_https connect %s success", host, port, remote_sock.ip)

    if left_buf:
        ssl_sock.send(left_buf)
    sw = SocketWrap(ssl_sock, remote_sock.ip, port, host)
    sock.recved_times = 3
    g.pipe_socks.add_socks(sock, sw)


def do_socks(sock, host, port, client_address, left_buf=b""):
    if not g.x_tunnel:
        raise XTunnelNotRunning()

    try:
        conn_id = g.x_tunnel.proxy_session.create_conn(sock, host, port, True)
    except Exception as e:
        xlog.warn("do_sock to %s:%d, x_tunnel fail:%r", host, port, e)
        raise XTunnelNotRunning()

    if not conn_id:
        xlog.warn("x_tunnel create conn fail")
        raise XTunnelNotRunning()

    # xlog.debug("do_socks %r connect to %s:%d conn_id:%d", client_address, host, port, conn_id)
    if left_buf:
        g.x_tunnel.global_var.session.conn_list[conn_id].transfer_received_data(left_buf)
    g.x_tunnel.global_var.session.conn_list[conn_id].start(block=True)


def do_unwrap_socks(sock, host, port, client_address, req, left_buf=b""):
    if not g.x_tunnel:
        return

    try:
        remote_sock = socks.create_connection(
            (host, port),

View on GitHub (pinned to cfa5bc17b6)

Solutions

  1. Ensure X-Tunnel is enabled and logged in so g.x_tunnel.proxy_session exists before traffic is routed to it
  2. Check X-Tunnel login status/log for the root cause of the tunnel not running
  3. Adjust smart_router rules or goagent config so socks traffic prefers a working strategy (direct/GAE) when tunnel is down
  4. Catch XTunnelNotRunning in try_loop to fall back to the next route (this is the designed behavior)

Example fix

// conceptual
# before
conn_id = g.x_tunnel.proxy_session.create_conn(sock, host, port, True)

# after
if not g.x_tunnel or not getattr(g.x_tunnel, 'proxy_session', None):
    raise XTunnelNotRunning()  # explicit check instead of relying on AttributeError
Defensive patterns

Strategy: type-guard

Validate before calling

def x_tunnel_ready():
    return bool(getattr(g, 'x_tunnel', None) and getattr(g.x_tunnel, 'proxy_session', None))

Type guard

def x_tunnel_ready() -> bool:
    xt = getattr(g, 'x_tunnel', None)
    return xt is not None and getattr(xt, 'proxy_session', None) is not None

Try / catch

try:
    do_socks(...)
except XTunnelNotRunning:
    try_next_strategy(sock, host, port)

Prevention

When it happens

Trigger: A SOCKS connection is routed to the X-Tunnel strategy while g.x_tunnel is None (X-Tunnel not logged in / not enabled), or proxy_session is missing because the tunnel stopped.

Common situations: X-Tunnel account not configured or login failed at startup, tunnel service shut down mid-run, deployment where only GAE proxy is enabled but routing rules still send traffic to X-Tunnel.

Related errors


AI-assisted analysis of XX-net/XX-Net@cfa5bc17b6 (2026-08-27). Data as JSON: /api/errors/2032a4c1ba08ad7e. Report an issue: GitHub.