{"record":{"id":"bd602e1a3cbd2827","repo":"XTLS/Xray-core","slug":"invalid-outbound","errorCode":null,"errorMessage":"invalid outbound","messagePattern":"invalid outbound","errorType":"exception","errorClass":"errors.Error","httpStatus":null,"severity":"error","filePath":"proxy/dns/dns.go","lineNumber":159,"sourceCode":"func (h *Handler) applyRules(qType dnsmessage.Type, domain string) (RuleAction, dnsmessage.RCode) {\n\tqCode := uint16(qType)\n\tfor _, r := range h.rules {\n\t\tif r.Apply(qCode, domain) {\n\t\t\treturn r.action, r.rCode\n\t\t}\n\t}\n\tif qType == dnsmessage.TypeA || qType == dnsmessage.TypeAAAA {\n\t\treturn RuleAction_Hijack, dnsmessage.RCodeSuccess\n\t}\n\treturn RuleAction_Return, dnsmessage.RCodeSuccess\n}\n\n// Process implements proxy.Outbound.\nfunc (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.Dialer) error {\n\toutbounds := session.OutboundsFromContext(ctx)\n\tob := outbounds[len(outbounds)-1]\n\tif !ob.Target.IsValid() {\n\t\treturn errors.New(\"invalid outbound\")\n\t}\n\tob.Name = \"dns\"\n\n\tsrcNetwork := ob.Target.Network\n\n\tdest := ob.Target\n\tif h.rewriteServer.Network != net.Network_Unknown {\n\t\tdest.Network = h.rewriteServer.Network\n\t}\n\tif h.rewriteServer.Address != nil {\n\t\tdest.Address = h.rewriteServer.Address\n\t}\n\tif h.rewriteServer.Port != 0 {\n\t\tdest.Port = h.rewriteServer.Port\n\t}\n\n\terrors.LogInfo(ctx, \"handling DNS traffic to \", dest)\n","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/dns/dns.go#L141-L177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{ \"type\":\"field\", \"outboundTag\":\"dns-out\", \"network\":\"tcp,udp\" }\n\n// after\n{ \"type\":\"field\", \"outboundTag\":\"dns-out\", \"network\":\"udp\", \"port\": 53 }","handlingStrategy":"validation","validationCode":"// in routing-rule generation, assert dns outbound is only matched by DNS queries\nfunc ruleIsDNSOnly(r Rule) bool { return r.OutboundTag == \"dns-out\" && r.Network == \"udp\" && r.Port == 53 }","typeGuard":"func hasValidTarget(ctx context.Context) bool {\n    obs := session.OutboundsFromContext(ctx)\n    if len(obs) == 0 { return false }\n    t := obs[len(obs)-1].Target\n    return t.IsValid() && t.Address != nil\n}","tryCatchPattern":"if err := dnsHandler.Process(ctx, link, d); err != nil {\n    if err.Error() == \"invalid outbound\" { skipAndLog(ctx); return nil }\n    return err\n}","preventionTips":["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"],"tags":["go","xray","dns","routing","session"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}