XTLS/Xray-core · warning · errors.Error
connection ends
Error message
connection ends
What it means
In the DNS handler's TCP query loop, request and response copy tasks run under task.Run; when either task returns an error the aggregate is wrapped as "connection ends". It signals the client- or server-side connection terminated before the DNS exchange completed cleanly — EOF mid-query, read/write failure, or the UDP/TCP relay closing.
Source
Thrown at proxy/dns/dns.go:307
b, err := connReader.ReadMessage()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
timer.Update()
if err := writer.WriteMessage(b); err != nil {
return err
}
}
}
if err := task.Run(ctx, request, response); err != nil {
return errors.New("connection ends").Base(err)
}
return nil
}
func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter, timer *signal.ActivityTimer) {
var ips []net.IP
var ttl uint32
var err error
switch qType {
case dnsmessage.TypeA:
ips, ttl, err = h.client.LookupIP(domain, dns.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: true,
})
case dnsmessage.TypeAAAA:View on GitHub (pinned to 7d214f8b09)
Solutions
- Check the chained Base(err): EOF means the peer closed, RST/reset means network policy, context.Canceled means shutdown
- Verify the upstream DNS server (h.nonIPQuery / server config) is reachable and answers reliably
- If it occurs only at shutdown/reload, it is benign — queries die with the instance; ignore in logs
- Stabilize the path (MTU, firewall rules for port 53 TCP/UDP) if resets recur
Example fix
// before: shutdown noise treated as fatal
if err := h.handleTCP(ctx, link); err != nil { log.Fatal(err) }
// after: tolerate connection teardown during shutdown/reload
if err := h.handleTCP(ctx, link); err != nil {
if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "use of closed") {
return nil
}
return err
} Defensive patterns
Strategy: try-catch
Try / catch
if err := h.handleQueryLoop(ctx, link); err != nil {
if errors.Is(err, context.Canceled) || isConnClosedErr(err) { return nil } // teardown is benign
logQueryFailure(ctx, err)
return err
} Prevention
- Log at warn level, not fatal, for DNS connection teardown during reload
- Keep upstream resolvers healthy and close (latency)
- Drain contexts gracefully on shutdown so in-flight queries finish
When it happens
Trigger: DNS client disconnects before the answer arrives; the remote DNS endpoint resets the connection; socket read/write errors inside the relay goroutines; context cancellation while a query is in flight during shutdown/reload.
Common situations: Short browser timeouts racing slow upstream resolvers; firewall RST-ing long-lived DNS-over-TCP; Xray instance shutting down (config reload) while queries are outstanding; flaky mobile networks.
Related errors
- failed to resolve ip for target ${domain}
- failed to process outbound traffic
- unknown action: {}
- rCode out of range: {}
- legacy nonIPQuery and blockTypes cannot be mixed with rules
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/4c8537a6a8ec4fe7.
Report an issue: GitHub.