egametang/ET · error · RpcException

location lock failed key: {key} actorId: {actorId} error: {r

Error message

location lock failed key: {key} actorId: {actorId} error: {response.Message}

What it means

Thrown by LocationProxyComponent.LockWithToken when the RPC response from the primary Location scene returns a non-success error code. This wraps the server-side error with proxy-level context. The most common underlying cause is ERR_LocationAlreadyLocked (another actor holds the lock) or ERR_LocationLockOwnerMismatch (a different actor owns the route entry).

Source

Thrown at Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationProxyComponentSystem.cs:235

                    $"location add failed key: {key} actorId: {actorId} error: {response.Message}");
            }
        }

        public static async ETTask<long> LockWithToken(this LocationProxyComponent self, int type, long key, ActorId actorId,
            int time = 60000)
        {
            Log.Info($"location proxy lock {key}, {actorId} {self.GetSingleton<TimeInfo>().ServerNow()}");

            ObjectLockRequest request = ObjectLockRequest.Create();
            request.Type = type;
            request.Key = key;
            request.ActorId = actorId;
            request.Time = time;

            ObjectLockResponse response = (ObjectLockResponse)await self.CallPrimaryWithRetry(key, request);
            if (response.Error != ErrorCode.ERR_Success)
            {
                throw new RpcException(response.Error,
                    $"location lock failed key: {key} actorId: {actorId} error: {response.Message}");
            }

            return response.LockToken;
        }

        [Obsolete("Use LockWithToken and pass the returned token to UnLock.", true)]
        public static async ETTask Lock(this LocationProxyComponent self, int type, long key, ActorId actorId,
            int time = 60000)
        {
            await self.LockWithToken(type, key, actorId, time);
        }

        [Obsolete("Use UnLock overload with lockToken.", true)]
        public static ETTask UnLock(this LocationProxyComponent self, int type, long key, ActorId oldActorId,
            ActorId newActorId)
        {
            throw new RpcException(ErrorCode.ERR_LocationLockTokenMismatch,

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Catch RpcException and inspect e.Error: ERR_LocationAlreadyLocked requires waiting for the lock to release or expire before retrying.
  2. For ERR_LocationLockOwnerMismatch, ensure the actorId matches the current route owner before locking.
  3. Implement a retry loop with backoff at the application level for transient lock conflicts.
  4. For ERR_LocationPrimaryUnavailable after exhaustion, verify Location scene topology.

Example fix

// before -- unhandled lock
long token = await locationProxy.LockWithToken(type, key, actorId, 60000);

// after -- retry on lock conflict with backoff
long token = 0;
for (int i = 0; i < maxRetries; i++)
{
    try
    {
        token = await locationProxy.LockWithToken(type, key, actorId, 60000);
        break;
    }
    catch (RpcException e) when (e.Error == ErrorCode.ERR_LocationAlreadyLocked && i < maxRetries - 1)
    {
        await root.TimerComponent.WaitAsync(100 * (i + 1));
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    token = await locationProxy.LockWithToken(type, key, actorId, 60000);
}
catch (RpcException e) when (e.Error == ErrorCode.ERR_LocationAlreadyLocked)
{
    // Retry with backoff or fail gracefully
    Log.Warning($"Lock conflict on key {key}: {e.Message}");
}
catch (RpcException e) when (e.Error == ErrorCode.ERR_LocationLockOwnerMismatch)
{
    Log.Warning($"Lock owner mismatch on key {key}: {e.Message}");
}

Prevention

When it happens

Trigger: LocationProxyComponent.LockWithToken(type, key, actorId, time) calls CallPrimaryWithRetry, gets response.Error != ERR_Success. LockWithToken does NOT internally retry on ERR_LocationAlreadyLocked (that is not in the retry-eligible set), so a lock conflict surfaces immediately as this exception.

Common situations: Another actor already holds the lock (ERR_LocationAlreadyLocked); the route entry is owned by a different actor (ERR_LocationLockOwnerMismatch); primary was unavailable after all retries (ERR_LocationPrimaryUnavailable).

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/92f66b0505ded054. Report an issue: GitHub.