XTLS/Xray-core · error · errors.Error

failed to find an available destination

Error message

failed to find an available destination

What it means

setUpHTTPTunnel was retried with ExponentialBackoff(5, 100ms) and every attempt failed — dialing the proxy, TLS/ALPN negotiation, the CONNECT round-trip, or writing the first payload. After exhausting retries the last error is wrapped as "failed to find an available destination".

Source

Thrown at proxy/http/client.go:116

	header, err := fillRequestHeader(ctx, c.header)
	if err != nil {
		return errors.New("failed to fill out header").Base(err)
	}

	if err := retry.ExponentialBackoff(5, 100).On(func() error {
		netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, header, firstPayload)
		if netConn != nil {
			if _, ok := netConn.(*http2Conn); !ok {
				if _, err := netConn.Write(firstPayload); err != nil {
					netConn.Close()
					return err
				}
			}
			conn = stat.Connection(netConn)
		}
		return err
	}); err != nil {
		return errors.New("failed to find an available destination").Base(err)
	}

	defer func() {
		if err := conn.Close(); err != nil {
			errors.LogInfoInner(ctx, err, "failed to closed connection")
		}
	}()

	p := c.policyManager.ForLevel(0)
	if user != nil {
		p = c.policyManager.ForLevel(user.Level)
	}

	var newCtx context.Context
	var newCancel context.CancelFunc
	if session.TimeoutOnlyFromContext(ctx) {
		newCtx, newCancel = context.WithCancel(context.Background())
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Unwrap the Base error to see the last attempt's actual failure (dial vs non-200 vs TLS)
  2. Test the proxy by hand: `curl -x http://user:pass@proxy:3128 https://target -v`
  3. Fix credentials/allowlist/port policy on the proxy side
  4. If non-200, check the proxy's response code — 407 means auth, 403 means policy
Defensive patterns

Strategy: retry

Validate before calling

```go
// one-shot probe before trusting the outbound
if err := probeHTTPTunnel(ctx, proxyDest, user, dialer); err != nil {
    // surface proxy misconfig early instead of 5 blind retries
}
```

Try / catch

```go
if err := c.Process(ctx, link, dialer); err != nil {
    if strings.Contains(err.Error(), "failed to find an available destination") {
        base := errors.Unwrap(err) // last retry's cause: dial / non-200 / TLS
        // only retry on transient dial errors; fix auth/ACL otherwise
    }
}
```

Prevention

When it happens

Trigger: HTTP proxy server down/unreachable, CONNECT rejected with non-200 (auth failure, forbidden target), TLS handshake failure when TLS is in play, or first-payload write after non-h2 CONNECT failing repeatedly. The 5-attempt backoff amplifies transient errors into a single final failure.

Common situations: Wrong credentials in settings.servers[].users, proxy requiring allowlisting the Xray host's IP, proxy that blocks CONNECT to non-443 ports, cached h2 conn going stale (CanTakeNewRequest false) forcing fresh failures.

Related errors


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