XTLS/Xray-core · error · errors.Error

failed to dispatch request

Error message

failed to dispatch request

What it means

After the dokodemo inbound has built reader/writer and a valid destination, it hands the link to the dispatcher via DispatchLink. If the dispatcher rejects the dispatch, the error is wrapped here. Causes are structural: missing default outbound, no matching routing outcome, or dispatcher-level context/inbound failures — the specific reason is chained in Base(err).

Source

Thrown at proxy/dokodemo/dokodemo.go:199

			if d.sockopt != nil {
				mark = int(d.sockopt.Mark)
			}
			pConn, err := FakeUDP(addr, mark)
			if err != nil {
				return err
			}
			writer = NewPacketWriter(pConn, &dest, mark, back)
			defer writer.(*PacketWriter).Close() // close fake UDP conns
		}
	}

	if err := dispatcher.DispatchLink(
		ctx, dest, &transport.Link{
			Reader: reader,
			Writer: writer,
		},
	); err != nil {
		return errors.New("failed to dispatch request").Base(err)
	}
	return nil // Unlike Dispatch(), DispatchLink() will not return until the outbound finishes Process()
}

func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer {
	writer := &PacketWriter{
		conn:  conn,
		conns: make(map[net.Destination]net.PacketConn),
		mark:  mark,
		back:  back,
	}
	writer.conns[*d] = conn
	return writer
}

type PacketWriter struct {
	conn  net.PacketConn
	conns map[net.Destination]net.PacketConn

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Read the chained Base(err) to see which outbound/rule failed
  2. Ensure every outboundTag in routing rules matches an existing outbound tag
  3. Keep a valid first outbound (e.g. freedom or blackhole) as the default
  4. Re-run the boot after fixes to confirm the dispatcher accepts the link

Example fix

// before: rule points at removed outbound
{"routing":{"rules":[{"type":"field","ip":["geoip:private"],"outboundTag":"old-block"}]}}

// after
{"routing":{"rules":[{"type":"field","ip":["geoip:private"],"outboundTag":"block"}]},
 "outbounds":[{"protocol":"blackhole","tag":"block"}]}
Defensive patterns

Strategy: validation

Validate before calling

// verify every routing rule's outboundTag exists before boot
tags := map[string]bool{}
for _, o := range config.Outbounds { tags[o.Tag] = true }
for _, r := range config.Routing.Rules { if !tags[r.OutboundTag] { return fmt.Errorf("dangling outboundTag %s", r.OutboundTag) } }

Try / catch

if err := d.dispatch(ctx, dest, link); err != nil {
    if strings.Contains(err.Error(), "failed to dispatch request") { reportRoutingIntegrity(err); return err }
    return err
}

Prevention

When it happens

Trigger: DispatchLink returning an error: config with no usable outbound for the resolved tag, routing rule referencing a nonexistent outboundTag, or dispatcher failing to create the outbound handler (which can itself stem from outbound Init errors).

Common situations: Renaming/removing an outbound but leaving a routing rule pointing at the old tag; configs where the first outbound is not a valid default; handler-level init failures inside the chained outbound.

Related errors


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