XTLS/Xray-core · error

write packet data: %w

Error message

write packet data: %w

What it means

writePacketWithLength encodes all fields into a frame and then writes it atomically with writeFull; this error wraps that final write failing. It is the outermost write error for any outbound packet, so any underlying connection problem (closed, reset, deadline) shows up here after the frame was built successfully.

Source

Thrown at transport/internet/finalmask/xmc/protocol.go:389

	if err != nil {
		return 0, fmt.Errorf("read byte: %w", err)
	}

	return buf[0], nil
}

func writePacket(w io.Writer, packetID int, fields ...field) error {
	_, err := writePacketWithLength(w, packetID, fields...)
	return err
}

func writePacketWithLength(w io.Writer, packetID int, fields ...field) (int, error) {
	frame, err := encodePacket(packetID, fields...)
	if err != nil {
		return 0, err
	}
	if err = writeFull(w, frame); err != nil {
		return 0, fmt.Errorf("write packet data: %w", err)
	}
	return len(frame), nil
}

func encodePacket(packetID int, fields ...field) ([]byte, error) {
	var dataBuf bytes.Buffer

	for _, field := range fields {
		err := field.writeTo(&dataBuf)
		if err != nil {
			return nil, fmt.Errorf("write packet field: %w", err)
		}
	}
	if dataBuf.Len() > maxPacketDataLength {
		return nil, fmt.Errorf("write packet: bad length: %d", dataBuf.Len())
	}

	packetIDVarint := Varint(packetID)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Once writePacketWithLength returns this error, treat the connection as dead — do not retry on the same conn.
  2. Classify the wrapped error (closed vs timeout vs reset) for metrics/alerting.
  3. Size write deadlines to your largest padded frame.
  4. Route sends through a single writer goroutine to avoid close/write races.
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := writePacketWithLength(w, id, fields...); err != nil {
    teardownConn()
    var nerr net.Error
    if errors.As(err, &nerr) && nerr.Timeout() {
        return fmt.Errorf("frame flush timed out (deadline too small?): %w", err)
    }
    return fmt.Errorf("connection lost while sending packet %d: %w", id, err)
}

Prevention

When it happens

Trigger: writePacket on a connection the peer already closed; write deadline exceeded while flushing a large frame; conn closed locally by error handling while a packet send was queued.

Common situations: Sending keepalive/login packets right as the server drops the connection; slow links where big padded frames exceed deadlines; races between connection teardown and pending sends.

Related errors


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