egametang/ET · warning · RpcException
location get retry exceeded key: {key} retry: {retryCount}/{
Error message
location get retry exceeded key: {key} retry: {retryCount}/{self.locationRequestRetryTimes} What it means
Get received ERR_LocationGetRetry from the location server, meaning the requested key is currently locked (the entity is being transferred between server processes). The proxy retried with escalating backoff (delay = locationRequestRetryIntervalMs * retryCount) up to locationRequestRetryTimes (default 20, interval default 100ms). All retries returned LocationGetRetry, so the lock was never released within the total retry window.
Source
Thrown at Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationProxyComponentSystem.cs:400
ObjectGetResponse response = (ObjectGetResponse)await self.CallPrimaryWithRetry(key, request);
if (response.Error == ErrorCode.ERR_Success)
{
return response.ActorId;
}
if (response.Error == ErrorCode.ERR_LocationGetRetry)
{
++retryCount;
self = selfRef;
if (self == null)
{
throw new Exception("location proxy disposed");
}
if (retryCount >= self.locationRequestRetryTimes)
{
throw new RpcException(response.Error,
$"location get retry exceeded key: {key} retry: {retryCount}/{self.locationRequestRetryTimes}");
}
int delayMs = self.locationRequestRetryIntervalMs * retryCount;
if (delayMs <= 0)
{
delayMs = 1;
}
Scene root = self.Root();
EntityRef<Scene> rootRef = root;
await root.TimerComponent.WaitAsync(delayMs);
root = rootRef;
if (root == null)
{
throw new Exception("location proxy root disposed");
}
continue;View on GitHub (pinned to 5cab01f7a8)
Solutions
- Increase locationRequestRetryTimes on the LocationProxyComponent (set in Awake, default 20) for environments with slow transfers.
- Investigate why the lock is held so long — check for crashed processes that acquired location locks without releasing them.
- Catch RpcException with ERR_LocationGetRetry and implement a higher-level retry with longer backoff or circuit-breaking.
- Reduce the lock timeout in LockWithToken so orphaned locks expire faster.
Example fix
// before — default retry times (20) may be too few
// proxy.locationRequestRetryTimes = 20 (set in Awake)
ActorId id = await proxy.Get(type, key); // throws after 20 retries
// after — increase retry budget
public override void Awake(LocationProxyComponent self)
{
self.locationRequestRetryTimes = 50;
self.locationRequestRetryIntervalMs = 200;
} Defensive patterns
Strategy: retry
Try / catch
// Catch at the application level and implement longer backoff retry:
int appRetry = 0;
while (true)
{
try
{
ActorId id = await proxy.Get(type, key);
return id;
}
catch (RpcException e) when (e.Error == ErrorCode.ERR_LocationGetRetry)
{
if (++appRetry > 5)
throw;
await root.TimerComponent.WaitAsync(2000 * appRetry);
}
} Prevention
- Increase locationRequestRetryTimes for slow-transfer environments.
- Monitor for stuck location locks — a lock held beyond its timeout indicates a crashed process.
- Reduce lock timeout so orphaned locks expire faster, unblocking Get callers.
- Use UnLockWithRetry to ensure locks are always released even after transient errors.
When it happens
Trigger: Get(type, key) while another process holds a location lock on the same key for longer than the cumulative retry window (~20 retries with escalating delays). The lock owner hasn't called UnLock within the retry budget.
Common situations: Actor migration/transfer taking longer than expected due to slow serialization or network. A lock that was acquired but never released because the locking process crashed before calling UnLock. Slow database causing lock operations to stall. locationRequestRetryTimes set too low for the deployment.
Related errors
- ERR_LocationGetRetry
- ERR_LocationPrimaryUnavailable
- ERR_LocationPrimaryUnavailable
- location primary actor id is empty: {primarySceneName}
- location proxy message sender is null: {self.Root().Name}
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/8fcb6a2e5ce2409e.
Report an issue: GitHub.