NetworkManager Error messages after stopping and restarting a host

[EDIT: This is in Unity 5.4.2f2, by the way…]

I encountered this issue in a much more complex project, but I’ve stripped it back to the simplest thing I could write to demonstrate the problem. Do the following:

  1. Set up a project with a new scene. Add a GameObject, and onto that object add a NetworkManager, a NetworkManagerHUD, and the following “MyNetworkTest” script. Set the PlayerPrefab on the NetworkManager to be a basic prefab just containing a NetworkIdentity and nothing else.
  2. Run the “game”. Click on “LAN Host(H)” to set up the instance as a host.
  3. Click on “Send Test Message” to send a message from the local client to the server. Note in the console window that the server has received the message.
  4. Click on “Stop (X)” to stop the server. If you feel like it, click “Send Test Message” again and note that it shows the error message you would expect.
  5. Click on “LAN Host(H)” again to start back up as a host again. Click “Send Test Message” again. Instead of the console log indicating that the server received the message, you see the following mysterious error:

Local invoke: Failed to find local connection to invoke handler on [connectionId=0] for MsgId:1234

Does anyone know what that’s about, and what I would need to do in order for a host to be able to shut down and start up again cleanly?

Additionally, if you build this game and run another instance of it on the local network, connecting as a client, then after you turn the host off and on again and reconnect the client (it automatically disconnects when the Host stops), then attempting to send the test message from the client results in this error on the server:

Unknown message ID 1234 connId:1

Here’s my test code:

using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.NetworkSystem;

public class MyNetworkTest : MonoBehaviour
{
	const int TEST_MESSAGE_ID = 1234;

	NetworkManager _networkManager;

	void Start()
	{
		_networkManager = GetComponent<NetworkManager>();

		NetworkServer.RegisterHandler(TEST_MESSAGE_ID, OnClientTestMessage);
	}

	void OnGUI()
	{
		if(GUI.Button(new Rect(250, 40, 200, 20), "Send Test Message"))
		{
			if(_networkManager != null && _networkManager.client != null && _networkManager.client.isConnected)
			{
				IntegerMessage intMessage = new IntegerMessage();
				intMessage.value = 42;
				_networkManager.client.Send(TEST_MESSAGE_ID, intMessage);
			}
			else
			{
				Debug.LogError("Client not connected, can't send test message");
			}
		}
	}

	void OnClientTestMessage(NetworkMessage netMsg)
	{
		IntegerMessage intMsg = netMsg.ReadMessage<IntegerMessage>();
		Debug.Log(string.Format("Server received OnClientTestMessage connectionID: {0} messageData: {1}", netMsg.conn.connectionId, intMsg.value));
	}
}

I figured this out with some help from a colleague, by the way. The catch is that the line:

NetworkServer.RegisterHandler(TEST_MESSAGE_ID, OnClientTestMessage);

Occurs in Start(), which means it’s only called once. In my more complex version of the code, I had a class which inherited from NetworkManager and contained all my custom handlers, but still had all its RegisterHandler() calls inside Start(). Moving them to OnServerReady() appears to solve to problem, since the handlers will be re-registered every time the server reconnects.

It wasn’t clear to me from reading the documentation that you need to call RegisterHandlers every time the server (and presumably the client as well, for messages going back the other way) connects or reconnects.