I am encountering reproducible Relay connection failure when using Netcode for GameObjects + Unity Transport (UTP).
Netcode Relay is not working. The error appears during the transport early update phase:
Failed to connect to server.
UnityEngine.Debug:LogError (object)
Unity.Netcode.Transports.UTP.UnityTransport:ProcessEvent () (at ./Library/PackageCache/com.unity.netcode.gameobjects@bd2a018756ed/Runtime/Transports/UTP/UnityTransport.cs:1010)
Unity.Netcode.Transports.UTP.UnityTransport:OnEarlyUpdate () (at ./Library/PackageCache/com.unity.netcode.gameobjects@bd2a018756ed/Runtime/Transports/UTP/UnityTransport.cs:1063)
Unity.Netcode.NetworkTransport:EarlyUpdate () (at ./Library/PackageCache/com.unity.netcode.gameobjects@bd2a018756ed/Runtime/Transports/NetworkTransport.cs:131)
Unity.Netcode.NetworkManager:NetworkUpdate (Unity.Netcode.NetworkUpdateStage) (at ./Library/PackageCache/com.unity.netcode.gameobjects@bd2a018756ed/Runtime/Core/NetworkManager.cs:341)
Unity.Netcode.NetworkUpdateLoop:RunNetworkUpdateStage (Unity.Netcode.NetworkUpdateStage) (at ./Library/PackageCache/com.unity.netcode.gameobjects@bd2a018756ed/Runtime/Core/NetworkUpdateLoop.cs:191)
Unity.Netcode.NetworkUpdateLoop/NetworkEarlyUpdate/<>c:<CreateLoopSystem>b__0_0 () (at ./Library/PackageCache/com.unity.netcode.gameobjects@bd2a018756ed/Runtime/Core/NetworkUpdateLoop.cs:214)
This happens after successfully:
- Initializing Unity Services
- Signing in anonymously
- Joining a Relay allocation using a valid join code
- Calling
SetRelayServerData - Calling
NetworkManager.StartClient()
No exceptions are thrown during Relay join allocation or client start.
Environment
- Unity version: (please assume recent LTS if relevant)
- Transport: com.unity.transport @ 2.6.0
- Relay: Unity Relay Service
- Platform: Android (also tested in Editor)
- Connection type: UDP
NOTE: All of the following code execute successfully. No error.
Client Join Code (Context)
public async Task JoinAsync(string joinCode)
{
await EnsureServicesAsync();
if (_networkManager.IsListening)
_networkManager.Shutdown();
var allocation = await RelayService.Instance.JoinAllocationAsync(joinCode);
var serverData = AllocationUtils.ToRelayServerData(allocation, "udp");
_unityTransport.SetRelayServerData(serverData);
// Yield one frame before starting client
await Task.Yield();
_networkManager.StartClient();
}
Authentication is guaranteed before joining:
private async Task EnsureServicesAsync()
{
if (UnityServices.State == ServicesInitializationState.Uninitialized)
await UnityServices.InitializeAsync();
if (!AuthenticationService.Instance.IsSignedIn)
await AuthenticationService.Instance.SignInAnonymouslyAsync();
while (!AuthenticationService.Instance.IsSignedIn)
await Task.Yield();
}
Additional Context: Successful Raw Relay Join Request
Note: The presence of a non-empty hostConnectionData value (for example, "TlwhkVL8geh1ObNysgmVnshr0IKKOx4+xyEEv/3mGia+nyUeqXqRnNWkC0Lm9LY7+cU=") indicates that a host has successfully connected to the Relay allocation. This confirms that the headless Netcode host is actively running and that the Relay server is functioning correctly, as this field is only populated once the host is established and sending heartbeats.
To rule out Relay service or credential issues, I tested the same join code using a raw REST request.
The request consistently succeeds and returns a valid allocation with endpoints.
Request
curl --location 'https://relay-allocations.services.api.unity.com/v1/join' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <player_access_token>' \
--data '{
"joinCode": "9899P6"
}'
Response (200 OK)
- Valid
allocationId - Valid
connectionData,hostConnectionData, andkey - Valid Relay server endpoints:
udp : 34.158.45.226:37000
dtls : 34.158.45.226:37001
wss : *.relay.cloud.unity3d.com:37011
This suggests:
- Join code is valid
- Token is valid
- Allocation exists and is reachable
- Relay service itself is functioning correctly
- The presence of a non-empty
hostConnectionDatavalue (for example,"TlwhkVL8geh1ObNysgmVnshr0IKKOx4+xyEEv/3mGia+nyUeqXqRnNWkC0Lm9LY7+cU=") indicates Netcode host is actively running and that the Relay server is functioning correctly, as this field is only populated once the host is established and sending heartbeats.
curl --location 'https://relay-allocations.services.api.unity.com/v1/join' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5...' \
--data '{
"joinCode": "9899P6"
}'
RESPONSE:
{
"data": {
"allocation": {
"allocationId": "6c9a0c4e-7400-4a78-8ebb-07fea8a2b73c",
"allocationIdBytes": "bJoMTnQASniOuwf+qKK3PA==",
"connectionData": "zmV8e6DVTHBG3Bvw2wHewJxznbPSoa6ml/n5B8OovzHqgqRBsigCkVf/rRuCqpJ3854AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"hostConnectionData": "TlwhkVL8geh1ObNysgmVnshr0IKKOx4+xyEEv/3mGia+nyUeqXqRnNWkC0Lm9LY7+cU=",
"key": "/O5JRiInXu78ZGKIFhSI5POMAYc6xvP5zmW3rn+RfD9daTDofT6cOf9xkFUJy1szCaByYdS3e0dWbmRylG3WkQ==",
"region": "asia-southeast1",
"relayServer": {
"ipV4": "34.158.45.226",
"port": 37000
},
"serverEndpoints": [
{
"connectionType": "udp",
"host": "34.158.45.226",
"network": "udp",
"port": 37000,
"reliable": false,
"secure": false
},
{
"connectionType": "dtls",
"host": "34.158.45.226",
"network": "udp",
"port": 37001,
"reliable": false,
"secure": true
},
{
"connectionType": "wss",
"host": "6790645139760809820-asia-southeast1.relay.cloud.unity3d.com",
"network": "tcp",
"port": 37011,
"reliable": true,
"secure": true
}
]
}
},
"meta": {
"requestId": "65d3649d-60b0-496d-89bc-224dc68be6d4",
"status": 200
}
}