XTLS/Xray-core · error

failed to dispatch request to ${destination}

Error message

failed to dispatch request to ${destination}

What it means

The routing dispatcher refused to open an outbound link for the destination requested by the trojan client (dispatcher.Dispatch failed). Dispatch resolves the destination through routing rules and dials the first outbound; failure means no route matched, the outbound errored, or the destination is invalid/unreachable.

Source

Thrown at proxy/trojan/server.go:334

	if err := task.Run(ctx, requestDone); err != nil {
		return err
	}
	return nil
}

func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session,
	destination net.Destination,
	clientReader buf.Reader,
	clientWriter buf.Writer, dispatcher routing.Dispatcher,
) error {
	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
	ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)

	link, err := dispatcher.Dispatch(ctx, destination)
	if err != nil {
		return errors.New("failed to dispatch request to ", destination).Base(err)
	}

	requestDone := func() error {
		defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
		if buf.Copy(clientReader, link.Writer, buf.UpdateActivity(timer)) != nil {
			return errors.New("failed to transfer request").Base(err)
		}
		return nil
	}

	responseDone := func() error {
		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

		if err := buf.Copy(link.Reader, clientWriter, buf.UpdateActivity(timer)); err != nil {
			return errors.New("failed to write response").Base(err)
		}
		return nil
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Check routing rules: does a rule with action 'block' or a bogus outboundTag match this destination
  2. Verify the outboundTag in rules exists in outbounds and that outbound can dial (test it directly)
  3. Look at the Base error in the log — it carries the dispatcher's own failure reason (e.g. 'failed to get outbound handler' or dial timeout)
  4. If DNS inside dispatch fails, fix the configured DNS servers or use domainStrategy ipResolve on the outbound

Example fix

// json: make sure the tag referenced by rules exists
"routing": {"rules": [{"type": "field", "ip": ["geoip:private"], "outboundTag": "direct"}]},
"outbounds": [{"tag": "direct", "protocol": "freedom"}]
Defensive patterns

Strategy: validation

Validate before calling

// before dispatching, sanity-check the destination shape
func validDest(d net.Destination) bool {
    return d.Port > 0 && d.Address != nil &&
        (d.Network == net.Network_TCP || d.Network == net.Network_UDP)
}

Try / catch

link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
    errors.LogError(ctx, errors.New("failed to dispatch request to ", destination).Base(err))
    return err // per-connection failure; do not crash the inbound
}

Prevention

When it happens

Trigger: Routing rules send the destination to a tag that does not exist (balancer/strategy typo), the selected outbound fails to dial (freedom with blocked network, proxy outbound down), or the destination address is malformed (e.g. empty domain after client-side resolution).

Common situations: Config references an outbound tag removed in an edit; 'block' rule matched unintentionally; upstream proxy credentials expired; DNS failure inside dispatch.

Related errors


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