XTLS/Xray-core · error · errors.Error

Proxy responded with non 200 code: {status}

Error message

Proxy responded with non 200 code: {status}

What it means

HTTP/1.1 path of setUpHTTPTunnel: the proxy answered the CONNECT request, but the response status was not 200. The full status line (code + reason) is embedded in the message, so 407/403/502 are directly readable. The rawConn is closed and the error propagates to the retry loop.

Source

Thrown at proxy/http/client.go:243

	connectHTTP1 := func(rawConn net.Conn) (net.Conn, error) {
		req.Header.Set("Proxy-Connection", "Keep-Alive")

		err := req.Write(rawConn)
		if err != nil {
			rawConn.Close()
			return nil, err
		}

		resp, err := http.ReadResponse(bufio.NewReader(rawConn), req)
		if err != nil {
			rawConn.Close()
			return nil, err
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			rawConn.Close()
			return nil, errors.New("Proxy responded with non 200 code: " + resp.Status)
		}
		return rawConn, nil
	}

	connectHTTP2 := func(rawConn net.Conn, h2clientConn *http2.ClientConn) (net.Conn, error) {
		pr, pw := io.Pipe()
		req.Body = pr

		var pErr error
		var wg sync.WaitGroup
		wg.Add(1)

		go func() {
			_, pErr = pw.Write(firstPayload)
			wg.Done()
		}()

		resp, err := h2clientConn.RoundTrip(req)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Read the status in the message: 407 → fix credentials; 403 → adjust proxy ACL for the target/port; 502 → target unreachable from proxy
  2. If the proxy only allows CONNECT 443, restrict targets or switch outbound type
  3. Verify with curl: `curl -x http://proxy:3128 -p https://target -v` and compare status lines
  4. Handle captive-portal/proxy-auth environments before routing traffic
Defensive patterns

Strategy: try-catch

Validate before calling

```go
// manual CONNECT probe
req, _ := http.NewRequest(http.MethodConnect, targetAddr, nil)
resp, err := http.DefaultTransport.(*http.Transport).RoundTrip(req)
if err == nil && resp.StatusCode != 200 { /* fix auth/ACL before deploy */ }
```

Try / catch

```go
if err := c.Process(ctx, link, dialer); err != nil {
    if strings.Contains(err.Error(), "non 200 code") {
        status := extractStatus(err) // 407 auth, 403 policy, 502 upstream
        // map to config fix; do not retry auth failures
    }
}
```

Prevention

When it happens

Trigger: CONNECT to the configured HTTP proxy returns any non-200: 407 (proxy auth required / bad credentials), 403 (target not allowed by proxy policy), 502/503 (proxy cannot reach target), 451, etc.

Common situations: Wrong user/pass in settings.servers[].users, proxy allowlists blocking the client IP or destination port, corporate proxies restricting CONNECT to 443 only, captive portals intercepting with 302/403.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/2365997f5ecc1a20. Report an issue: GitHub.