XTLS/Xray-core · warning

failed to flush payload

Error message

failed to flush payload

What it means

Thrown by the trojan client when unbuffering the connection writer (bufferWriter.SetBuffered(false)) fails after the prime payload copy. Flushing pushes the trojan header plus the first payload bytes to the wire; any writer/TLS error at this point surfaces as this warning.

Source

Thrown at proxy/trojan/client.go:124

			Target:  destination,
			Account: account,
		}

		var bodyWriter buf.Writer
		if destination.Network == net.Network_UDP {
			bodyWriter = &PacketWriter{Writer: connWriter, Target: destination}
		} else {
			bodyWriter = connWriter
		}

		// write some request payload to buffer
		if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
			return errors.New("failed to write A request payload").Base(err).AtWarning()
		}

		// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
		if err = bufferWriter.SetBuffered(false); err != nil {
			return errors.New("failed to flush payload").Base(err).AtWarning()
		}

		// Send header if not sent yet
		if _, err = connWriter.Write([]byte{}); err != nil {
			return err.(*errors.Error).AtWarning()
		}

		if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
			return errors.New("failed to transfer request payload").Base(err).AtInfo()
		}

		return nil
	}

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

		var reader buf.Reader

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Read the Base error to distinguish connection-reset from TLS failures.
  2. Verify password and TLS settings (serverName, ALPN h2/http/1.1) match the trojan server.
  3. Raise policy timeouts (handshake/connectionIdle) if very slow links cause premature cancels.
  4. Compare client and server xray-core versions — trojan header/timing behavior changed across releases.
Defensive patterns

Strategy: try-catch

Try / catch

if err := client.Process(ctx, link, dialer); err != nil {
	if strings.Contains(err.Error(), "failed to flush payload") {
		// inspect base error for reset-vs-TLS cause; verify serverName/ALPN/password
	}
}

Prevention

When it happens

Trigger: The underlying buffered writer's Flush returns an error: trojan connection already reset by peer, TLS layer failed to write (cert/ALPN problem on very early data), or the connWriter was closed by the inactivity timer firing during the 100ms prime window.

Common situations: Server RST right after handshake (auth rejected); aggressive connectionIdle policy cancelling the context before the flush; middlebox interference on early TLS application data.

Related errors


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