XTLS/Xray-core · warning

failed to dial to ${dest}

Error message

failed to dial to ${dest}

What it means

Dialing the fallback destination failed after retry.ExponentialBackoff(5, 100ms) exhausted all attempts (dialer.DialContext(fb.Type, fb.Dest)). fb.Dest is a string address; fb.Type is typically 'tcp' or 'unix'. Marked AtWarning because the original trojan failure is already logged.

Source

Thrown at proxy/trojan/server.go:463

	fb := pfb[path]
	if fb == nil {
		return errors.New(`failed to find the default "path" config`).AtWarning()
	}

	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
	ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)

	var conn net.Conn
	if err := retry.ExponentialBackoff(5, 100).On(func() error {
		var dialer net.Dialer
		conn, err = dialer.DialContext(ctx, fb.Type, fb.Dest)
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return errors.New("failed to dial to " + fb.Dest).Base(err).AtWarning()
	}
	defer conn.Close()

	serverReader := buf.NewReader(conn)
	serverWriter := buf.NewWriter(conn)

	postRequest := func() error {
		defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
		if fb.Xver != 0 {
			ipType := 4
			remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
			if err != nil {
				ipType = 0
			}
			localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
			if err != nil {
				ipType = 0
			}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Confirm the fallback backend is listening: ss -tlnp | grep <port> from the xray host
  2. Correct the dest string in the fallback config (and type: 'unix' needs an absolute socket path)
  3. Check local firewall/SELinux for the xray process's right to dial that dest
  4. For unix sockets, ensure file permissions allow the xray user

Example fix

// json: point fallback at a verified listener
"fallbacks": [{"dest": "127.0.0.1", "port": 8080, "xver": 0}]
Defensive patterns

Strategy: retry

Validate before calling

// preflight the fallback target before enabling it
func destAlive(network, addr string) bool {
    c, err := net.DialTimeout(network, addr, time.Second)
    if err != nil { return false }
    c.Close()
    return true
}

Try / catch

if err := retry.ExponentialBackoff(5, 100).On(dialFallback); err != nil {
    // backing off already happened; surface config/infra problem, do not hot-loop
    return errors.New("failed to dial to " + fb.Dest).Base(err).AtWarning()
}

Prevention

When it happens

Trigger: The fallback dest service is down, the address/port in the fallback config is wrong, a unix socket path does not exist, or the local firewall blocks the loopback connection.

Common situations: Nginx/web server behind the fallback not running, dest typo ('127.0.0.1:80' vs 'localhost:443'), SELinux/AppArmor blocking dials, or unix socket permission mismatch after privilege drop.

Related errors


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