Quick answer: The most common cause is that the NetworkObject is not spawned on the network. ClientRpc calls only work on NetworkBehaviour components attached to GameObjects with a spawned NetworkObject. If you instantiate a prefab with Instantiate() instead of NetworkManager.SpawnManager.
Here is how to fix Unity netcode clientrpc not received. The server calls a ClientRpc and nothing happens on the clients. No error, no warning, no callback. The method simply never executes on the receiving end. This is one of the most frustrating networking bugs because there is no obvious failure point—the server thinks it sent the message, and the client has no idea it was supposed to receive one. Here is every reason ClientRpc calls silently fail in Unity Netcode for GameObjects and how to fix each one.
How ClientRpc Works in Netcode
A ClientRpc is a method marked with the [ClientRpc] attribute on a NetworkBehaviour component. When the server calls this method, Netcode serializes the parameters and sends them to all connected clients (or specific clients via ClientRpcParams). Each client then deserializes the parameters and executes the method locally.
For this to work, several conditions must be met: the NetworkObject must be spawned, the method must follow the correct naming convention (ending in ClientRpc), and the call must originate from the server.
Solution 1: Ensure the NetworkObject Is Spawned
The number one cause of silent ClientRpc failures is that the GameObject exists in the scene but its NetworkObject is not spawned on the network. This happens when you use Instantiate() instead of the network-aware spawn methods.
using Unity.Netcode;
using UnityEngine;
public class NetworkSpawnManager : NetworkBehaviour
{
[SerializeField] private GameObject projectilePrefab;
// WRONG: This creates a local-only object — RPCs will not work
public void SpawnProjectileBroken()
{
GameObject obj = Instantiate(projectilePrefab, transform.position, Quaternion.identity);
// obj has no network presence — ClientRpc calls on it go nowhere
}
// CORRECT: Spawn through the network system
[ServerRpc]
public void SpawnProjectileServerRpc()
{
GameObject obj = Instantiate(projectilePrefab, transform.position, Quaternion.identity);
NetworkObject netObj = obj.GetComponent<NetworkObject>();
if (netObj == null)
{
Debug.LogError("Prefab is missing NetworkObject component.");
Destroy(obj);
return;
}
// Spawn on the network — now RPCs will work
netObj.Spawn();
// Now this ClientRpc will reach all clients
obj.GetComponent<Projectile>().NotifySpawnClientRpc();
}
}
You can verify spawn status at runtime by checking NetworkObject.IsSpawned. Add a debug check before any ClientRpc call to catch this early:
public void SafeClientRpcCall()
{
if (!IsSpawned)
{
Debug.LogError($"Cannot send ClientRpc — {gameObject.name} is not spawned.");
return;
}
if (!IsServer)
{
Debug.LogError("ClientRpc can only be called from the server.");
return;
}
MyActionClientRpc();
}
[ClientRpc]
private void MyActionClientRpc()
{
Debug.Log("ClientRpc received on client.");
}
Solution 2: Fix the ServerRpc to ClientRpc Pattern
A common mistake is trying to call a ClientRpc directly from a client. In Netcode for GameObjects, only the server can invoke ClientRpc methods. The correct pattern is: client calls ServerRpc, server validates and then calls ClientRpc.
using Unity.Netcode;
using UnityEngine;
public class ChatSystem : NetworkBehaviour
{
// WRONG: Client cannot call ClientRpc directly
public void SendChatBroken(string message)
{
// This will log a warning and be ignored if called from a client
BroadcastMessageClientRpc(message);
}
// CORRECT: Client calls ServerRpc, server calls ClientRpc
public void SendChat(string message)
{
// Client sends to server
SendChatServerRpc(message);
}
[ServerRpc(RequireOwnership = false)]
private void SendChatServerRpc(string message, ServerRpcParams rpcParams = default)
{
// Server validates the message
if (string.IsNullOrEmpty(message) || message.Length > 200)
return;
// Get the sender's client ID for attribution
ulong senderId = rpcParams.Receive.SenderClientId;
// Server broadcasts to all clients
BroadcastMessageClientRpc(message, senderId);
}
[ClientRpc]
private void BroadcastMessageClientRpc(string message, ulong senderId)
{
Debug.Log($"Chat from client {senderId}: {message}");
// Update UI with the chat message
}
}
Note the RequireOwnership = false on the ServerRpc. By default, ServerRpc can only be called by the owner of the NetworkObject. For shared systems like chat, you need to disable this restriction so any client can send messages through the server.
Solution 3: Send ClientRpc to Specific Clients
Sometimes you want to send a ClientRpc to only one client or a subset of clients. Use ClientRpcParams to target specific recipients. If you forget to include the params, the method sends to all clients by default.
using Unity.Netcode;
using UnityEngine;
using System.Collections.Generic;
public class TargetedRpcExample : NetworkBehaviour
{
// Send damage notification only to the player who was hit
public void NotifyDamage(ulong targetClientId, float damage)
{
if (!IsServer) return;
ClientRpcParams clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = new ulong[] { targetClientId }
}
};
ShowDamageClientRpc(damage, clientRpcParams);
}
[ClientRpc]
private void ShowDamageClientRpc(float damage, ClientRpcParams clientRpcParams = default)
{
Debug.Log($"You took {damage} damage!");
// Show damage UI, screen shake, etc.
}
// Send to multiple specific clients
public void NotifyTeam(List<ulong> teamClientIds, string message)
{
if (!IsServer) return;
ClientRpcParams clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = teamClientIds.ToArray()
}
};
TeamMessageClientRpc(message, clientRpcParams);
}
[ClientRpc]
private void TeamMessageClientRpc(string message, ClientRpcParams clientRpcParams = default)
{
Debug.Log($"Team message: {message}");
}
}
The ClientRpcParams parameter must be the last parameter in the method signature and must have a default value. If you place it before other parameters or omit the default, Netcode will not recognize the method as a valid ClientRpc.
Solution 4: Debug NetworkObject State
When ClientRpc calls fail silently, add comprehensive logging to trace the exact point of failure. Check spawn state, ownership, server authority, and connection status.
using Unity.Netcode;
using UnityEngine;
public class NetworkDebugHelper : NetworkBehaviour
{
public void DiagnoseRpcIssue()
{
Debug.Log($"--- RPC Diagnostic for {gameObject.name} ---");
Debug.Log($"IsSpawned: {IsSpawned}");
Debug.Log($"IsServer: {IsServer}");
Debug.Log($"IsClient: {IsClient}");
Debug.Log($"IsHost: {IsHost}");
Debug.Log($"IsOwner: {IsOwner}");
Debug.Log($"OwnerClientId: {OwnerClientId}");
Debug.Log($"NetworkObjectId: {NetworkObjectId}");
Debug.Log($"Connected clients: {NetworkManager.Singleton.ConnectedClientsList.Count}");
foreach (var client in NetworkManager.Singleton.ConnectedClientsList)
{
Debug.Log($" Client {client.ClientId} connected");
}
}
}
“Networking bugs are invisible by nature. The server thinks it sent the message, the client does not know it missed one. Logging on both sides is not optional—it is the only way to find where the chain breaks.”
Related Issues
If your ClientRpc arrives but with incorrect or stale data, see Fix: Unity Netcode NetworkVariable Not Syncing. For issues where NetworkObjects fail to spawn on clients, check Fix: Unity Netcode NetworkObject Spawn Failure. To collect network-related bug reports from multiplayer playtest sessions, read Bug Reporting Tools for Unity Developers.
Always verify IsSpawned before calling any RPC. Use the ServerRpc-to-ClientRpc pattern for client-initiated actions. Check RequireOwnership settings on ServerRpc. Log on both server and client to find where the chain breaks. Test with a real network connection, not just host mode.