XTLS/Xray-core · error · errors.Error

failed to open connection to {destination}

Error message

failed to open connection to {destination}

What it means

The low-level dial (dialer.Dial inside the retry task) failed and the raw error is wrapped as "failed to open connection to <destination>". This is the generic transport-establishment failure for the freedom outbound: TCP/UDP connect, dialer timeout, or asockopt-level refusal. The original dial error is preserved via .Base(err).

Source

Thrown at proxy/freedom/freedom.go:350

				errors.LogInfo(ctx, "dialing to ", dialDest)
			}
		}
		if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
			blockedDest = &dialDest
			blockedRule = rule
			return nil
		}

		rawConn, err := dialer.Dial(ctx, dialDest)
		if err != nil {
			return err
		}

		conn = rawConn
		return nil
	})
	if err != nil {
		return errors.New("failed to open connection to ", destination).Base(err)
	}
	if blockedDest != nil {
		delay := h.blockDelay(blockedRule)
		errors.LogInfo(ctx, "blocked target: ", *blockedDest, ", blackholing connection for ", delay)
		timer := time.AfterFunc(delay, func() {
			common.Interrupt(input)
			common.Interrupt(output)
			errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *blockedDest)
		})
		defer timer.Stop()
		defer common.Close(output)
		if err := buf.Copy(input, buf.Discard); err != nil {
			return nil
		}
		return nil
	}
	if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
		version := byte(h.config.ProxyProtocol)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Read the Base error — "connection refused" vs "i/o timeout" vs "network is unreachable" point to different fixes
  2. Test reachability from the Xray host: `nc -vz <host> <port>` / `curl -v`
  3. If IPv6 fails, use domainStrategy UseIPv4 or fix IPv6 routing
  4. Raise policy.handshake timeout for slow links; check sockopt (tcpFastOpen, interface) validity
Defensive patterns

Strategy: retry

Validate before calling

```go
conn, err := net.DialTimeout("tcp", dest.NetAddr(), 3*time.Second)
if err != nil { /* destination unreachable; fail early with clear message */ }
conn.Close()
```

Try / catch

```go
if err := h.Process(ctx, link, dialer); err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() { /* retry or backoff */ }
}
```

Prevention

When it happens

Trigger: Direct outbound to an unreachable destination: connection refused, no route to host, network timeout under the policy handshake timeout, or a sockopt dialer (e.g. via dialerProxy) failing. UDP destinations can also fail here when the OS rejects sendto on a constrained network.

Common situations: Target firewall drops SYNs (shows as i/o timeout), IPv6 destination on an IPv4-only host, firewall-blocked egress on VPS/container, policy timeout too small for high-latency links, or a chained dialerProxy whose own dial failed first.

Related errors


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