XX-net/XX-Net · warning

send_conn_data but not running

Error message

send_conn_data but not running

What it means

send_conn_data is invoked (from create_conn, transfer_received_data, transfer_ack, or transfer_peer_close) with data for a connection, but proxy_session.running is False — the session is stopped or was never successfully started. The upload is dropped with this warning because there is no transport to send on.

Solutions

  1. Only route client traffic after session.start() succeeds; gate the local proxy listener on session.running.
  2. Retry the request after the session is re-established (login succeeds and running is True).
  3. During shutdown, close accepted client sockets first so handlers don't attempt uploads on a dead session.

Example fix

# before
sock = listener.accept(); session_conn.send_conn_data(conn_id, data)

# after
if not session.running:
    session.start()
if session.running:
    session.send_conn_data(conn_id, data)
Defensive patterns

Strategy: validation

Validate before calling

if not proxy_session.running:
    proxy_session.start()
assert proxy_session.running, 'tunnel not running'
proxy_session.send_conn_data(conn_id, data)

Type guard

def session_active(session) -> bool:
    return bool(getattr(session, 'running', False))

Prevention

When it happens

Trigger: Any client traffic arriving after session stop() (or after a failed start/login), e.g. an in-flight HTTP proxy request whose upload path runs while the session is shutting down or re-logging-in.

Common situations: Restart/relogin windows where the local proxy still accepts client connections; requests in flight when the tunnel drops; code that starts the proxy listener before verifying session.start() returned True.

Related errors


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

Appendix: source

Thrown at code/default/x_tunnel/local/proxy_session.py:529

                pass
        # self.conn_list = {}
        xlog.debug("stop all connection finished")

    def remove_conn(self, conn_id):
        try:
            if conn_id in self.conn_list:
                conn = self.conn_list[conn_id]
                # xlog.debug("remove conn:%d %s:%d", conn_id, conn.host, conn.port)
                del self.conn_list[conn_id]
        except Exception as e:
            xlog.warn("remove conn:%d except:%r", conn_id, e)

        if len(self.conn_list) == 0:
            self.target_on_roads = 0

    def send_conn_data(self, conn_id, data):
        if not self.running:
            xlog.warn("send_conn_data but not running")
            return

        # xlog.debug("upload conn:%d, len:%d", conn_id, len(data))
        buf = base_container.WriteBuffer()
        buf.append(struct.pack("<II", conn_id, len(data)))
        buf.append(data)
        self.send_buffer.put(buf)

        if self.oldest_received_time == 0:
            self.oldest_received_time = time.time()
        elif self.send_buffer.pool_size > g.config.max_payload:
            # xlog.debug("notify on send conn data")
            self.wait_queue.notify()

    @staticmethod
    def sn_payload_head(sn, payload):
        return struct.pack("<II", sn, len(payload))

View on GitHub (pinned to cfa5bc17b6)