XTLS/Xray-core · error

write minecraft keep-alive: %w

Error message

write minecraft keep-alive: %w

What it means

writeKeepAlive failed to write a 0x04 keep-alive reply (client side, triggered from Read) or periodic keep-alive (server side). The wrapped writePacket error means the underlying connection write failed — broken pipe, closed conn, or write deadline exceeded.

Source

Thrown at transport/internet/finalmask/xmc/packet_stream.go:165

	var channel String
	if err := channel.readFrom(r); err != nil {
		return nil, false, fmt.Errorf("read minecraft custom payload channel: %w", err)
	}
	if string(channel) != packetChannel {
		return nil, false, nil
	}
	payload := make([]byte, r.Len())
	if _, err := io.ReadFull(r, payload); err != nil {
		return nil, false, fmt.Errorf("read minecraft custom payload data: %w", err)
	}
	return payload, true, nil
}

func (s *packetStream) writeKeepAlive(id Long) error {
	s.writeMu.Lock()
	defer s.writeMu.Unlock()
	if err := writePacket(s.writer, configurationKeepAlive, &id); err != nil {
		return fmt.Errorf("write minecraft keep-alive: %w", err)
	}
	return nil
}

func (s *packetStream) keepAliveLoop() {
	ticker := time.NewTicker(keepAlivePeriod)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			id := Long(s.keepAliveID.Add(1))
			if err := s.writeKeepAlive(id); err != nil {
				return
			}
		case <-s.done:
			return
		}
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Inspect the wrapped error (EPIPE, ECONNRESET, os.ErrDeadlineExceeded) for the true cause
  2. Mark the connection dead and tear it down; keep-alive failure is fatal by design
  3. Ensure network path allows bidirectional traffic and keep-alive interval (15s) is shorter than NAT idle timeouts
  4. Reconnect at the application layer
Defensive patterns

Strategy: try-catch

Try / catch

if err := stream.Write(payload); err != nil {
    if strings.Contains(err.Error(), "write minecraft keep-alive") {
        conn.Close() // keep-alive path is dead, connection must be rebuilt
    }
    return err
}

Prevention

When it happens

Trigger: Client receives a server keep-alive but the connection has since died; server's 15-second keepAliveLoop ticker fires after the peer vanished; write deadline set during handshake is still active.

Common situations: Peer abruptly disappears (crash, NAT timeout); asymmetric connectivity loss where reads still succeed but writes fail; long-running tunnels through aggressive firewalls.

Related errors


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