egametang/ET · critical · Exception
kchannel connected but kcp is zero!
Error message
kchannel connected but kcp is zero!
What it means
KChannel.Send throws when IsConnected is true but the kcp instance is null. This is an internal invariant violation: the connected state and the kcp lifecycle are out of sync, meaning the channel was disposed or never fully created while its flag says connected.
Source
Thrown at Packages/cn.etetet.core/Scripts/Core/Share/Network/KChannel.cs:408
this.kcp.Send(memoryStream.GetBuffer().AsSpan((int)memoryStream.Position + alreadySendCount, sendCount));
alreadySendCount += sendCount;
}
}
this.Service.AddToUpdate(0, this.Id);
}
public void Send(MemoryBuffer memoryBuffer)
{
if (!this.IsConnected)
{
this.waitSendMessages.Enqueue(memoryBuffer);
return;
}
if (this.kcp == null)
{
throw new Exception("kchannel connected but kcp is zero!");
}
// 检查等待发送的消息,如果超出最大等待大小,应该断开连接
int n = (int)this.kcp.WaitSendCount;
int maxWaitSize = 0;
switch (this.Service.ServiceType)
{
case ServiceType.Inner:
maxWaitSize = Kcp.InnerMaxWaitSize;
break;
case ServiceType.Outer:
maxWaitSize = Kcp.OuterMaxWaitSize;
break;
default:
throw new ArgumentOutOfRangeException();
}
if (n > maxWaitSize)
{View on GitHub (pinned to 5cab01f7a8)
Solutions
- Do not Send on a channel that is being torn down; gate sends on both IsConnected and kcp != null.
- Ensure OnError/Dispose clears IsConnected before nulling kcp.
- Report as a framework bug if it reproduces with a clean connect/disconnect cycle.
Example fix
// before
public void Send(MemoryBuffer mb) {
if (!IsConnected) { waitSendMessages.Enqueue(mb); return; }
if (kcp == null) throw new Exception(...);
// after
public void Send(MemoryBuffer mb) {
if (!IsConnected || kcp == null) { waitSendMessages.Enqueue(mb); return; } Defensive patterns
Strategy: type-guard
Validate before calling
null
Type guard
public bool CanSend => IsConnected && kcp != null;
Try / catch
null
Prevention
- Gate sends on kcp != null, not only IsConnected.
- Clear IsConnected before nulling kcp in the dispose/error path.
- Treat this throw as a framework bug to file if it reproduces.
When it happens
Trigger: Calling Send after the kcp was disposed (e.g., on OnError/timeout path) but before IsConnected was cleared, or a connect handshake that set the flag without finishing kcp allocation.
Common situations: Disconnect/error race, double-dispose, or a version regression in the connect state machine.
Related errors
- bind error: {ipEndPoint}
- GetChannelConn conn not found KChannel! {channelId}
- default conn throw Exception! {channelId}
- bufferList length < count, {Length} {count}
- bufferList length < coutn, buffer length: {buffer.Length} {o
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/fd6c051f7899baca.
Report an issue: GitHub.