{"record":{"id":"29c9690bf26beddd","repo":"EllanJiang/GameFramework","slug":"you-must-connect-first","errorCode":null,"errorMessage":"You must connect first.","messagePattern":"You must connect first\\.","errorType":"exception","errorClass":"GameFrameworkException","httpStatus":null,"severity":"error","filePath":"GameFramework/Network/NetworkManager.NetworkChannelBase.cs","lineNumber":430,"sourceCode":"            }\n\n            /// <summary>\n            /// 向远程主机发送消息包。\n            /// </summary>\n            /// <typeparam name=\"T\">消息包类型。</typeparam>\n            /// <param name=\"packet\">要发送的消息包。</param>\n            public void Send<T>(T packet) where T : Packet\n            {\n                if (m_Socket == null)\n                {\n                    string errorMessage = \"You must connect first.\";\n                    if (NetworkChannelError != null)\n                    {\n                        NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);\n                        return;\n                    }\n\n                    throw new GameFrameworkException(errorMessage);\n                }\n\n                if (!m_Active)\n                {\n                    string errorMessage = \"Socket is not active.\";\n                    if (NetworkChannelError != null)\n                    {\n                        NetworkChannelError(this, NetworkErrorCode.SendError, SocketError.Success, errorMessage);\n                        return;\n                    }\n\n                    throw new GameFrameworkException(errorMessage);\n                }\n\n                if (packet == null)\n                {\n                    string errorMessage = \"Packet is invalid.\";\n                    if (NetworkChannelError != null)","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/EllanJiang/GameFramework/blob/d0c010b05167c58e92350449d04864a91ca13fd2/GameFramework/Network/NetworkManager.NetworkChannelBase.cs#L412-L448","documentation":"NetworkChannelBase.Send<T> checks that the channel's underlying Socket exists before enqueueing a packet. If m_Socket is null, the channel has never connected (or Dispose already ran), so GameFramework throws this GameFrameworkException (or fires NetworkChannelError with NetworkErrorCode.SendError if a handler is registered). It guards against sending on a channel with no socket.","triggerScenarios":"Calling Send<T> on an INetworkChannel obtained from networkManager.GetNetworkChannel/CreateNetworkChannel before ever calling Connect; calling Send after the channel was closed/Disposed (socket set to null); racing a send against channel disposal.","commonSituations":"Scripts that start sending in Unity Start/Awake before the async Connect completes or on a failed connection; sending after server disconnect handling disposed the channel; forgetting that each channel must be connected individually.","solutions":["Call channel.Connect(ipAddress, port, userData) and wait for the NetworkChannelConnected event before calling Send.","Check the channel's state (or track connection success) before each Send; skip or queue packets while not connected.","If the channel was disposed after a disconnect, create/reconnect a new channel via NetworkManager.CreateNetworkChannel instead of reusing the old one.","Register NetworkChannelError to receive SendError as an event instead of an unhandled exception."],"exampleFix":"// before\nchannel.Send(loginPacket); // throws if never connected\n// after\nchannel.Connected += (sender, e) => channel.Send(loginPacket);\nchannel.Connect(ipAddress, port, userData);","handlingStrategy":"validation","validationCode":"public static bool CanSend(INetworkChannel ch) => ch != null && ch.Id != 0 && IsConnected(ch); // track connection via NetworkChannelConnected/Closed events","typeGuard":"public static bool IsConnected(INetworkChannel ch) => connectedChannels.Contains(ch);","tryCatchPattern":"try { channel.Send(packet); } catch (GameFrameworkException ex) when (ex.Message == \"You must connect first.\") { QueueForLater(packet); }","preventionTips":["Only send after the NetworkChannelConnected event fires","Track channel lifetime; clear references on close/dispose","Queue outgoing packets while connecting and flush on connect","Register NetworkChannelError for centralized send-failure handling"],"tags":["network","socket","invalid-state","gameframework"],"backgroundTag":"invalid-state-transition","analyzedSha":"d0c010b05167c58e92350449d04864a91ca13fd2","analyzedAt":"2026-09-15T13:37:15.352Z","contentChangedAt":"2026-09-15T13:37:15.352Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}