XTLS/Xray-core · warning · errors.Error
connection ends
Error message
connection ends
What it means
Terminal wrapper around any error from the requestDone/responseDone task group: task.Run collects the first failure and freedom reports it as "connection ends". It is the outermost error a caller of Process sees, so the real cause ("failed to process request/response" or a task-level timeout/cancel) is one level down in the error chain.
Source
Thrown at proxy/freedom/freedom.go:459
}
var reader buf.Reader
if destination.Network == net.Network_TCP {
reader = buf.NewReader(conn)
} else {
reader = NewPacketReader(conn, h, defaultRule, UDPOverride, destination)
}
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
return errors.New("failed to process response").Base(err)
}
return nil
}
if newCtx != nil {
ctx = newCtx
}
if err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil {
return errors.New("connection ends").Base(err)
}
return nil
}
func NewPacketReader(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
iConn := conn
statConn, ok := iConn.(*stat.CounterConnection)
if ok {
iConn = statConn.Connection
}
var counter stats.Counter
if statConn != nil {
counter = statConn.ReadCounter
}
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
isOverridden := false
if UDPOverride.Address != nil || UDPOverride.Port != 0 {View on GitHub (pinned to 7d214f8b09)
Solutions
- Unwrap with errors.Unwrap/errors.Is to find the embedded cause before acting
- io.EOF / context.Canceled / io.ErrClosedPipe underneath are benign — route them to info-level logging instead of alerting
- If the cause is a timeout, adjust policy timeouts as in the process-request/response errors
- Do not retry blindly; retry only when the base cause is a network error, not EOF/cancel
Example fix
```go
err := freedomHandler.Process(ctx, link, dialer)
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, context.Canceled) {
// normal teardown
}
}
``` Defensive patterns
Strategy: try-catch
Type guard
```go
func isBenignTeardown(err error) bool {
return errors.Is(err, io.EOF) ||
errors.Is(err, context.Canceled) ||
errors.Is(err, io.ErrClosedPipe)
}
``` Try / catch
```go
err := h.Process(ctx, link, dialer)
if err != nil && !isBenignTeardown(err) {
cause := errors.Unwrap(err) // real failure lives here
log.Error().Err(cause).Msg("freedom connection failed")
}
``` Prevention
- Always unwrap before alerting
- Classify EOF/cancel as info-level
- Map child errors (566/567) to their own remedies
When it happens
Trigger: Either uplink or downlink copy fails, the context is cancelled (client disconnect propagates), or a policy timer aborts the task group. Essentially every non-dial failure of a freedom connection funnels here.
Common situations: Normal connection teardown being logged as an error; context cancellation when users close browsers/apps; timeouts as in 566/567.
Related errors
- connection ends
- failed to process data
- unsupported domain strategy: {}
- Invalid PacketsFrom
- PacketsFrom can't be 0
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/c9c7ce207f5f0fe3.
Report an issue: GitHub.