XX-net/XX-Net · warning

check_upload_not_acked found transfer_no:%d upload timeout:%

Error message

check_upload_not_acked found transfer_no:%d upload timeout:%f

What it means

In the round-trip path, check_upload_not_acked scans transfer_list for transfers whose upload has not been acknowledged by the server (server_received == False) and whose age exceeds g.config.send_timeout_retry, marking them 'timeout' and logging the elapsed time so they will be resent. It distinguishes a lost upload (this warning) from a lost download (server_sent timeout handled separately).

Source

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

        server_local_time = server_time - self.server_time_offset
        if self.server_time_deviation > g.config.server_time_max_deviation:
            return

        timeout_num = 0
        entry_time = time.time()
        with self.lock:
            now = time.time()
            if now - entry_time > 0.1:
                xlog.error("check_upload_not_acked lock time:%f", now - entry_time)
                return

            for no, data_info in self.transfer_list.items():
                if data_info["stat"] == "timeout":
                    continue

                if data_info["server_received"] == False and server_local_time - data_info["start_time"] > g.config.send_timeout_retry:
                    data_info["stat"] = "timeout"
                    xlog.warn("check_upload_not_acked found transfer_no:%d upload timeout:%f", no,
                              server_local_time - data_info["start_time"])
                    timeout_num += 1
                    continue

                if data_info["server_sent"] and server_time - data_info["server_sent"] > g.config.send_timeout_retry:
                    data_info["stat"] = "timeout"
                    xlog.warn("check_upload_not_acked found transfer_no:%d down timeout:%f", no,
                              server_time - data_info["server_sent"])
                    timeout_num += 1
                    continue

        if timeout_num:
            self.target_on_roads = \
                min(g.config.concurent_thread_num - g.config.min_on_road, self.target_on_roads + timeout_num)
            self.trigger_more()

    def process_server_received_transfer_no(self, server_received_no_list, server_sent_no_list, server_time):
        server_received_next_no = struct.unpack("<I", server_received_no_list.get(4))[0]

View on GitHub (pinned to cfa5bc17b6)

Solutions

  1. Raise g.config.send_timeout_retry to exceed your worst-case upload+ack latency, especially for large transfer chunks.
  2. Measure uplink quality (loss, bandwidth) and throttle concurent_thread_num to avoid saturating it.
  3. If acks are consistently slow while pings are fine, check relay/server load and switch front IPs (g.tls_relay_front).
  4. Rely on the built-in resend: transfers marked 'timeout' are retransmitted automatically.

Example fix

# before
send_timeout_retry = 4

# after
send_timeout_retry = 15
Defensive patterns

Strategy: retry

Prevention

When it happens

Trigger: A transfer's data never reached/registered on the server within send_timeout_retry seconds — upstream packet loss to the relay, a congested uplink, or a stalled server worker that received the data but never acked.

Common situations: Slow or lossy uplinks (asymmetric ADSL/satellite), uplink saturation by large uploads, relay overload, send_timeout_retry set lower than real upload+ack RTT, WiFi interference.

Understand the failure class

Related errors


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