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
- Confirm the fallback backend is listening: ss -tlnp | grep <port> from the xray host
- Correct the dest string in the fallback config (and type: 'unix' needs an absolute socket path)
- Check local firewall/SELinux for the xray process's right to dial that dest
- 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
- Health-check fallback backends alongside xray itself (systemd dependencies, upstream checks)
- Use 127.0.0.1:port rather than localhost to avoid IPv6-resolution surprises
- For unix sockets, confirm permissions survive xray's privilege drop
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
- Trojan fallbacks: "path" must be empty or start with "/"
- Trojan fallbacks: please fill in a valid value for every "de
- Trojan fallbacks: invalid PROXY protocol version, "xver" onl
- failed to find an available destination
- failed to find the default "name" config
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/02611ba2ce677fa3.
Report an issue: GitHub.