{"record":{"id":"4dd6d86d3354d84d","repo":"XTLS/Xray-core","slug":"failed-to-transport-all-udp-request-4dd6d8","errorCode":null,"errorMessage":"failed to transport all UDP request","messagePattern":"failed to transport all UDP request","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"proxy/shadowsocks/client.go","lineNumber":167,"sourceCode":"\t\tif err := task.Run(ctx, requestDone, responseDoneAndCloseWriter); err != nil {\n\t\t\treturn errors.New(\"connection ends\").Base(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif request.Command == protocol.RequestCommandUDP {\n\n\t\trequestDone := func() error {\n\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)\n\n\t\t\twriter := &UDPWriter{\n\t\t\t\tWriter:  conn,\n\t\t\t\tRequest: request,\n\t\t\t}\n\n\t\t\tif err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\treturn errors.New(\"failed to transport all UDP request\").Base(err)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\tresponseDone := func() error {\n\t\t\tdefer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)\n\n\t\t\treader := &UDPReader{\n\t\t\t\tReader: conn,\n\t\t\t\tUser:   user,\n\t\t\t}\n\n\t\t\tif err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {\n\t\t\t\treturn errors.New(\"failed to transport all UDP response\").Base(err)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/shadowsocks/client.go#L149-L185","documentation":"Thrown when the UDP request relay (link.Reader → UDPWriter over the Shadowsocks connection) fails before completion. Each UDP packet is individually framed (address header + payload) and AEAD-encrypted; any write error on the underlying connection or packet encoding failure aborts the whole UDP session. Usually the network path to the server dropped or the conn was closed by the peer/context.","triggerScenarios":"Dispatching UDP (DNS, QUIC, WebRTC) through the Shadowsocks client where buf.Copy from the inbound link to the UDPWriter errors: server closed the UDP-capable conn, context canceled, or AEAD packet encode fails.","commonSituations":"Server does not actually support UDP on that port or blocks it; NAT rewrites making the server reject the session; QUIC-heavy traffic (HTTP/3) hitting servers that throttle UDP; client switches networks mid-session.","solutions":["Confirm the server inbound has UDP enabled and the port is open for UDP (firewall allows UDP, not just TCP).","Test with a simple DNS query through the proxy to isolate QUIC-specific throttling.","If undesired, disable QUIC/UDP at the routing level (block quic or route UDP blackhole) so sessions do not half-fail.","Check server logs for the same instant to see whether it intentionally closed the session."],"exampleFix":"// before: routing lets all UDP through and the server blocks it\n// after: sinkhole QUIC so only TCP is proxied\n\"routing\": { \"rules\": [{ \"network\": \"udp\", \"port\": 443, \"outboundTag\": \"block\" }] }","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {\n  if isConnClosed(err) {\n    return nil // UDP flow ended; do not fail the whole session\n  }\n  return errors.New(\"failed to transport all UDP request\").Base(err)\n}","preventionTips":["Verify UDP reachability to the server before enabling UDP relay.","Block QUIC/UDP 443 in routing if the path cannot carry UDP reliably.","Use a dedicated UDP-capable outbound when the primary blocks UDP."],"tags":["shadowsocks","network","udp","relay","quic"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}