{"record":{"id":"6b65012280e4a308","repo":"XTLS/Xray-core","slug":"write-minecraft-keep-alive-w","errorCode":null,"errorMessage":"write minecraft keep-alive: %w","messagePattern":"write minecraft keep-alive: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/packet_stream.go","lineNumber":165,"sourceCode":"\tvar channel String\n\tif err := channel.readFrom(r); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"read minecraft custom payload channel: %w\", err)\n\t}\n\tif string(channel) != packetChannel {\n\t\treturn nil, false, nil\n\t}\n\tpayload := make([]byte, r.Len())\n\tif _, err := io.ReadFull(r, payload); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"read minecraft custom payload data: %w\", err)\n\t}\n\treturn payload, true, nil\n}\n\nfunc (s *packetStream) writeKeepAlive(id Long) error {\n\ts.writeMu.Lock()\n\tdefer s.writeMu.Unlock()\n\tif err := writePacket(s.writer, configurationKeepAlive, &id); err != nil {\n\t\treturn fmt.Errorf(\"write minecraft keep-alive: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (s *packetStream) keepAliveLoop() {\n\tticker := time.NewTicker(keepAlivePeriod)\n\tdefer ticker.Stop()\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tid := Long(s.keepAliveID.Add(1))\n\t\t\tif err := s.writeKeepAlive(id); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\tcase <-s.done:\n\t\t\treturn\n\t\t}\n\t}","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/packet_stream.go#L147-L183","documentation":"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.","triggerScenarios":"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.","commonSituations":"Peer abruptly disappears (crash, NAT timeout); asymmetric connectivity loss where reads still succeed but writes fail; long-running tunnels through aggressive firewalls.","solutions":["Inspect the wrapped error (EPIPE, ECONNRESET, os.ErrDeadlineExceeded) for the true cause","Mark the connection dead and tear it down; keep-alive failure is fatal by design","Ensure network path allows bidirectional traffic and keep-alive interval (15s) is shorter than NAT idle timeouts","Reconnect at the application layer"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := stream.Write(payload); err != nil {\n    if strings.Contains(err.Error(), \"write minecraft keep-alive\") {\n        conn.Close() // keep-alive path is dead, connection must be rebuilt\n    }\n    return err\n}","preventionTips":["Keep the 15s keep-alive interval below NAT/firewall idle timeouts","Close streams deterministically with Stop() when tearing down","Treat any keep-alive write failure as connection-fatal"],"tags":["go","network","minecraft","keep-alive","write"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}