XTLS/Xray-core · error

failed to process outbound traffic

Error message

failed to process outbound traffic

What it means

The primary outbound dispatch failure: the underlying proxy's Process(ctx, link, h) returned a non-nil error that is not one of the benign causes (io.EOF, io.ErrClosedPipe, context.Canceled), which are normalized to nil just above. The logged message wraps the real cause via .Base; the writer is interrupted and the error reported to the session originator.

Source

Thrown at app/proxyman/outbound/handler.go:253

			return
		}
		if h.mux.Enabled {
			test(h.mux.Dispatch(ctx, link))
			return
		}
	}
out:
	err := h.proxy.Process(ctx, link, h)
	var errC error
	if err != nil {
		errC = errors.Cause(err)
		if goerrors.Is(errC, io.EOF) || goerrors.Is(errC, io.ErrClosedPipe) || goerrors.Is(errC, context.Canceled) {
			err = nil
		}
	}
	if err != nil {
		// Ensure outbound ray is properly closed.
		err := errors.New("failed to process outbound traffic").Base(err)
		session.SubmitOutboundErrorToOriginator(ctx, err)
		errors.LogInfo(ctx, err.Error())
		common.Interrupt(link.Writer)
	} else {
		if errC != nil && goerrors.Is(errC, io.ErrClosedPipe) {
			common.Interrupt(link.Writer)
		} else {
			common.Close(link.Writer)
		}
	}
	common.Interrupt(link.Reader)
}

func (h *Handler) DestIpAddress() net.IP {
	return internet.DestIpAddress()
}

// Dial implements internet.Dialer.

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Inspect the full log line: the Base() error names the real failure (timeout, TLS, handshake, auth) — fix that layer first.
  2. Verify client/server protocol settings match exactly (protocol version, UUID/password, encryption, transport, TLS/REALITY parameters, SNI, path).
  3. Test raw reachability of the server's transport port (tcping/nc) and, for TLS/REALITY, confirm certificate and destination config; check server-side logs for the matching failure.
  4. For timeout-type inner errors, review sockopt dialer settings, mark/routing table, and MTU; for reset errors, check for ISP interference and switch transport (e.g. to grpc/ws over TLS).
  5. Reproduce with loglevel debug on both ends to capture the exact stage that fails.

Example fix

// no code fix; diagnosis example
// log: [Info] proxy/vless/outbound: failed to process outbound traffic > tls: handshake failure
// fix: align client streamSettings with server, e.g.
// before: "security": "tls", "tlsSettings": { "serverName": "wrong.example" }
// after:  "security": "tls", "tlsSettings": { "serverName": "actual.example" }
Defensive patterns

Strategy: retry

Validate before calling

// Pre-validate the remote before routing user traffic through it
if err := probeOutbound(ctx, handlerTag, probeDest); err != nil {
    return routeViaFallback(ctx, link)
}

Try / catch

// Classify cause before deciding: benign closes vs real failures
if err := dispatch(ctx, link); err != nil && strings.Contains(err.Error(), "failed to process outbound traffic") {
    switch {
    case isTimeoutCause(err): return retryWithBackoff(ctx, link, 3)
    case isAuthCause(err):   return nil // config problem; surface to user, no retry
    default:                 return fallbackOutbound.Dispatch(ctx, link)
    }
}

Prevention

When it happens

Trigger: h.proxy.Process fails for a connection that already passed DNS/mux handling: protocol errors from the remote server (handshake failure, auth failure, unsupported protocol), network errors dialing or mid-stream (connection reset, timeout), TLS failures, or the remote proxy closing with an error. Any cause except io.EOF / io.ErrClosedPipe / context.Canceled reaches this branch.

Common situations: Wrong UUID/password or altered protocol settings vs the server, TLS certificate/reality misconfiguration, server reachable but behind a CDN that rejects the path, NAT/firewall resetting long connections, or clock skew breaking time-bound handshakes. This is the generic envelope, so the Base cause in the log is the actual diagnostic.

Related errors


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