{"record":{"id":"a8985a44a8557547","repo":"XTLS/Xray-core","slug":"failed-to-dispatch-request-a8985a","errorCode":null,"errorMessage":"failed to dispatch request","messagePattern":"failed to dispatch request","errorType":"exception","errorClass":"errors.Error","httpStatus":null,"severity":"error","filePath":"proxy/dokodemo/dokodemo.go","lineNumber":199,"sourceCode":"\t\t\tif d.sockopt != nil {\n\t\t\t\tmark = int(d.sockopt.Mark)\n\t\t\t}\n\t\t\tpConn, err := FakeUDP(addr, mark)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\twriter = NewPacketWriter(pConn, &dest, mark, back)\n\t\t\tdefer writer.(*PacketWriter).Close() // close fake UDP conns\n\t\t}\n\t}\n\n\tif err := dispatcher.DispatchLink(\n\t\tctx, dest, &transport.Link{\n\t\t\tReader: reader,\n\t\t\tWriter: writer,\n\t\t},\n\t); err != nil {\n\t\treturn errors.New(\"failed to dispatch request\").Base(err)\n\t}\n\treturn nil // Unlike Dispatch(), DispatchLink() will not return until the outbound finishes Process()\n}\n\nfunc NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer {\n\twriter := &PacketWriter{\n\t\tconn:  conn,\n\t\tconns: make(map[net.Destination]net.PacketConn),\n\t\tmark:  mark,\n\t\tback:  back,\n\t}\n\twriter.conns[*d] = conn\n\treturn writer\n}\n\ntype PacketWriter struct {\n\tconn  net.PacketConn\n\tconns map[net.Destination]net.PacketConn","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/dokodemo/dokodemo.go#L181-L217","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Read the chained Base(err) to see which outbound/rule failed","Ensure every outboundTag in routing rules matches an existing outbound tag","Keep a valid first outbound (e.g. freedom or blackhole) as the default","Re-run the boot after fixes to confirm the dispatcher accepts the link"],"exampleFix":"// before: rule points at removed outbound\n{\"routing\":{\"rules\":[{\"type\":\"field\",\"ip\":[\"geoip:private\"],\"outboundTag\":\"old-block\"}]}}\n\n// after\n{\"routing\":{\"rules\":[{\"type\":\"field\",\"ip\":[\"geoip:private\"],\"outboundTag\":\"block\"}]},\n \"outbounds\":[{\"protocol\":\"blackhole\",\"tag\":\"block\"}]}","handlingStrategy":"validation","validationCode":"// verify every routing rule's outboundTag exists before boot\ntags := map[string]bool{}\nfor _, o := range config.Outbounds { tags[o.Tag] = true }\nfor _, r := range config.Routing.Rules { if !tags[r.OutboundTag] { return fmt.Errorf(\"dangling outboundTag %s\", r.OutboundTag) } }","typeGuard":null,"tryCatchPattern":"if err := d.dispatch(ctx, dest, link); err != nil {\n    if strings.Contains(err.Error(), \"failed to dispatch request\") { reportRoutingIntegrity(err); return err }\n    return err\n}","preventionTips":["Lint routing rules against outbound tags in CI","Always keep a valid default (first) outbound","Dry-run boot in staging after editing routing or outbounds"],"tags":["go","xray","dokodemo","dispatcher","routing"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}