XTLS/Xray-core · warning

connection ends

Error message

connection ends

What it means

Aggregate error returned by the trojan TCP relay when task.Run finishes with a failure in either the request or response pipe (wraps [724] or [725] typically). Before returning it interrupts both link ends so no goroutine or buffer leaks. It marks the end of a trojan connection, not a protocol defect per se.

Source

Thrown at proxy/trojan/server.go:358

			return errors.New("failed to transfer request").Base(err)
		}
		return nil
	}

	responseDone := func() error {
		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

		if err := buf.Copy(link.Reader, clientWriter, buf.UpdateActivity(timer)); err != nil {
			return errors.New("failed to write response").Base(err)
		}
		return nil
	}

	requestDonePost := task.OnSuccess(requestDone, task.Close(link.Writer))
	if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
		common.Must(common.Interrupt(link.Reader))
		common.Must(common.Interrupt(link.Writer))
		return errors.New("connection ends").Base(err)
	}

	return nil
}

func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.Session, connection stat.Connection, iConn stat.Connection, napfb map[string]map[string]map[string]*Fallback, first *buf.Buffer, firstLen int64, reader buf.Reader) error {
	if err := connection.SetReadDeadline(time.Time{}); err != nil {
		errors.LogWarningInner(ctx, err, "unable to set back read deadline")
	}
	errors.LogInfoInner(ctx, err, "fallback starts")

	name := ""
	alpn := ""
	if tlsConn, ok := iConn.(*tls.Conn); ok {
		cs := tlsConn.ConnectionState()
		name = cs.ServerName
		alpn = cs.NegotiatedProtocol
		errors.LogInfo(ctx, "realName = "+name)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Inspect the Base error chain to see which pipe failed and why
  2. If it floods the log during shutdown, reduce log level for the trojan inbound
  3. Fix the underlying copy failure per [724]/[725] guidance if it happens during active traffic
Defensive patterns

Strategy: try-catch

Try / catch

if err := task.Run(ctx, requestDonePost, responseDone); err != nil {
    common.Must(common.Interrupt(link.Reader))
    common.Must(common.Interrupt(link.Writer))
    return errors.New("connection ends").Base(err)
}

Prevention

When it happens

Trigger: Either requestDone or responseDone returned an error — i.e. any broken pipe during relaying — or the context was cancelled by the idle timer and a copy was treated as failure.

Common situations: Seen in bulk at server restart/shutdown (all connections torn down), during network churn, or after policy timeouts.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/2a92be9573a39382. Report an issue: GitHub.