XTLS/Xray-core · error · errors.Error
invalid outbound
Error message
invalid outbound
What it means
The DNS outbound handler (proxy/dns) Process() requires the current session's last outbound to carry a valid target, because it rewrites and forwards that target as the DNS server destination. If ob.Target is zero (network unknown AND address nil) the handler cannot function and returns this error immediately, before any I/O.
Source
Thrown at proxy/dns/dns.go:159
func (h *Handler) applyRules(qType dnsmessage.Type, domain string) (RuleAction, dnsmessage.RCode) {
qCode := uint16(qType)
for _, r := range h.rules {
if r.Apply(qCode, domain) {
return r.action, r.rCode
}
}
if qType == dnsmessage.TypeA || qType == dnsmessage.TypeAAAA {
return RuleAction_Hijack, dnsmessage.RCodeSuccess
}
return RuleAction_Return, dnsmessage.RCodeSuccess
}
// Process implements proxy.Outbound.
func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.Dialer) error {
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
if !ob.Target.IsValid() {
return errors.New("invalid outbound")
}
ob.Name = "dns"
srcNetwork := ob.Target.Network
dest := ob.Target
if h.rewriteServer.Network != net.Network_Unknown {
dest.Network = h.rewriteServer.Network
}
if h.rewriteServer.Address != nil {
dest.Address = h.rewriteServer.Address
}
if h.rewriteServer.Port != 0 {
dest.Port = h.rewriteServer.Port
}
errors.LogInfo(ctx, "handling DNS traffic to ", dest)
View on GitHub (pinned to 7d214f8b09)
Solutions
- Restrict the routing rule that targets the dns outbound to DNS traffic only (network: udp, port: 53)
- Never set the dns outbound as the first/default outbound; keep freedom/blackhole first
- Verify the paired inbound actually resolves original destination (see error 558 for dokodemo)
- If you need a plain DNS forwarder instead, configure a DNS module rather than routing raw traffic to the dns outbound
Example fix
// before
{ "type":"field", "outboundTag":"dns-out", "network":"tcp,udp" }
// after
{ "type":"field", "outboundTag":"dns-out", "network":"udp", "port": 53 } Defensive patterns
Strategy: validation
Validate before calling
// in routing-rule generation, assert dns outbound is only matched by DNS queries
func ruleIsDNSOnly(r Rule) bool { return r.OutboundTag == "dns-out" && r.Network == "udp" && r.Port == 53 } Type guard
func hasValidTarget(ctx context.Context) bool {
obs := session.OutboundsFromContext(ctx)
if len(obs) == 0 { return false }
t := obs[len(obs)-1].Target
return t.IsValid() && t.Address != nil
} Try / catch
if err := dnsHandler.Process(ctx, link, d); err != nil {
if err.Error() == "invalid outbound" { skipAndLog(ctx); return nil }
return err
} Prevention
- Never route broad traffic to the dns outbound; scope rules to udp/53
- Keep freedom as the first (default) outbound
- Test routing tables with dns+non-dns probe traffic before deploy
When it happens
Trigger: Routing non-DNS or target-less traffic to the "dns" outbound: e.g. a routing rule with outboundTag: dns matching a stream whose destination was not captured, or using the dns outbound as the default outbound for traffic lacking a destination.
Common situations: Copy-pasted routing configs where rules send all traffic (not just UDP port 53) to the dns outbound; using dns outbound with inbound types that do not produce a valid original-destination.
Related errors
- failed to resolve ip for target ${domain}
- outbound metadata not found
- balancing strategy returns empty tag
- unable to select outbounds
- unsupported GetPrincipleTarget
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/bd602e1a3cbd2827.
Report an issue: GitHub.