egametang/ET · warning · RpcException

ERR_LocationGetRetry

ERR_LocationGetRetry

Error message

location get retry type: {locationType} key: {key} actorId: {state.ActorId} lockToken: {state.LockToken}

What it means

Thrown by LocationComponent.Get when the requested key/type is currently locked (LockToken != 0) and the lock has not expired. Get refuses to return the actorId of a locked entry because the entry is in a transitional state -- the lock holder may be migrating or replacing the actor. The caller is expected to retry after the lock is released or expires.

Source

Thrown at Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationComponentSystem.cs:600

                    try
                    {
                        await self.SaveInfoToDB(locationInfo);
                    }
                    catch
                    {
                        self = selfRef;
                        if (self != null)
                        {
                            self.RestoreStates(key, snapshot);
                        }

                        throw;
                    }
                }
                else if (IsLocked(state))
                {
                    throw new RpcException(ErrorCode.ERR_LocationGetRetry,
                        $"location get retry type: {locationType} key: {key} actorId: {state.ActorId} lockToken: {state.LockToken}");
                }

                Log.Info($"location get type: {locationType} key: {key} actorId: {state.ActorId}");
                return state.ActorId;
            }
        }

        public static void RefreshPrimaryState(this LocationComponent self)
        {
            Scene root = self.Root();
            if (root == null)
            {
                return;
            }

            ServiceDiscoveryProxy serviceDiscoveryProxy = root.GetComponent<ServiceDiscoveryProxy>();
            if (serviceDiscoveryProxy == null)

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Use LocationProxyComponent.Get which automatically retries on ERR_LocationGetRetry up to 20 times (configurable via locationRequestRetryTimes) with increasing delay.
  2. If retries are exhausted, increase locationRequestRetryTimes or locationRequestRetryIntervalMs on the LocationProxyComponent.
  3. Ensure locks are released promptly -- check for leaked locks from crashed processes.
  4. If using time=0 locks, switch to finite-time locks so they auto-expire and unblock Get.

Example fix

// before -- direct Get on LocationComponent, no retry
ActorId id = await locationComponent.Get(type, key);

// after -- proxy Get with built-in retry
ActorId id = await locationProxy.Get(type, key);
Defensive patterns

Strategy: retry

Try / catch

// LocationProxyComponent.Get already retries ERR_LocationGetRetry internally.
// If you call LocationComponent.Get directly, wrap with retry:
for (int i = 0; i < maxRetries; i++)
{
    try { return await locationComponent.Get(type, key); }
    catch (RpcException e) when (e.Error == ErrorCode.ERR_LocationGetRetry && i < maxRetries - 1)
    {
        await root.TimerComponent.WaitAsync(100 * (i + 1));
    }
}

Prevention

When it happens

Trigger: Calling LocationComponent.Get(locationType, key) when TryGetRouteState returns a state with LockToken != 0 and IsExpiredLock is false (either LockExpireTime==0 for a permanent lock, or ServerNow() < LockExpireTime). The proxy-level Get catches ERR_LocationGetRetry and retries up to locationRequestRetryTimes with exponential backoff.

Common situations: An actor is being migrated (locked during migration) and another service tries to look it up; a long-running operation holds a lock with a large TTL; lock was acquired with time=0 (no expiry) and never released.

Related errors


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