XX-net/XX-Net · warning

forward_local read payload failed:%s

Error message

forward_local read payload failed:%s

What it means

In forward_local, the proxy tried to read the request body indicated by Content-Length from the client socket (self.rfile.read) and the read raised — usually a client disconnect, invalid Content-Length, or socket timeout — so the local forwarding is aborted.

Source

Thrown at code/default/gae_proxy/local/proxy_handler.py:104

        self.__class__.do_PUT = self.__class__.do_METHOD
        self.__class__.do_POST = self.__class__.do_METHOD
        self.__class__.do_HEAD = self.__class__.do_METHOD
        self.__class__.do_DELETE = self.__class__.do_METHOD
        self.__class__.do_OPTIONS = self.__class__.do_METHOD

    def forward_local(self):
        """
        If browser send localhost:xxx request to GAE_proxy,
        we forward it to localhost.
        """
        request_headers = dict((k.title(), v) for k, v in list(self.headers.items()))
        payload = b''
        if b'Content-Length' in request_headers:
            try:
                payload_len = int(request_headers.get(b'Content-Length', 0))
                payload = self.rfile.read(payload_len)
            except Exception as e:
                xlog.warn('forward_local read payload failed:%s', e)
                return

        response = simple_http_client.request(self.command, self.path, request_headers, payload)
        if not response:
            xlog.warn("forward_local fail, command:%s, path:%s, headers: %s, payload: %s",
                self.command, self.path, request_headers, payload)
            return

        out_list = []
        out_list.append(b"HTTP/1.1 %d\r\n" % response.status)
        for key in response.headers:
            key = key.title()
            out_list.append(b"%s: %s\r\n" % (key, response.headers[key]))
        out_list.append(b"\r\n")
        out_list.append(response.text)

        self.wfile.write(b"".join(out_list))

View on GitHub (pinned to cfa5bc17b6)

Solutions

  1. Verify the client actually sends the declared body length (curl -v / packet capture)
  2. Increase socket timeout if large uploads are being cut off
  3. Sanitize Content-Length (strip, validate digits) before int() to avoid ValueError on malformed headers
  4. Retry the request — transient client disconnects are common and benign

Example fix

# before
payload_len = int(request_headers.get(b'Content-Length', 0))
payload = self.rfile.read(payload_len)

# after
try:
    payload_len = int(request_headers.get(b'Content-Length', 0))
except ValueError:
    return
payload = self.rfile.read(payload_len)
Defensive patterns

Strategy: try-catch

Validate before calling

cl = request_headers.get(b'Content-Length', b'')
if cl and not cl.strip().isdigit():
    respond_400(); return

Try / catch

try:
    payload = self.rfile.read(payload_len)
except Exception as e:
    xlog.warn('forward_local read payload failed:%s', e)
    return  # simply drop the half-sent request; client is gone

Prevention

When it happens

Trigger: A client sends a request with a Content-Length header but closes the connection before sending the full body; Content-Length is non-numeric so int() raises; or the socket times out mid-body. read() raises and forward_local returns without forwarding.

Common situations: Browsers/tools aborting requests (page navigation, cancel), misbehaving HTTP clients sending malformed Content-Length, mobile clients dropping connections, aggressive timeouts on large uploads.

Related errors


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