egametang/ET · error · RpcException
location remove failed key: {key} expectedActorId: {expected
Error message
location remove failed key: {key} expectedActorId: {expectedActorId} error: {response.Message} What it means
Remove sent an ObjectRemoveRequest with an optional expectedActorId guard to the primary location server via CallPrimaryWithRetry. The server returned a non-success error, typically because expectedActorId didn't match the currently registered ActorId (concurrent modification) or because of an internal server error. The RpcException wraps the server's error code and message.
Source
Thrown at Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationProxyComponentSystem.cs:357
public static async ETTask Remove(this LocationProxyComponent self, int type, long key)
{
await self.Remove(type, key, default);
}
public static async ETTask Remove(this LocationProxyComponent self, int type, long key, ActorId expectedActorId)
{
Log.Info($"location proxy remove {key}, {self.GetSingleton<TimeInfo>().ServerNow()}");
ObjectRemoveRequest request = ObjectRemoveRequest.Create();
request.Type = type;
request.Key = key;
request.ExpectedActorId = expectedActorId;
ObjectRemoveResponse response = (ObjectRemoveResponse)await self.CallPrimaryWithRetry(key, request);
if (response.Error != ErrorCode.ERR_Success)
{
throw new RpcException(response.Error,
$"location remove failed key: {key} expectedActorId: {expectedActorId} error: {response.Message}");
}
}
public static async ETTask<ActorId> Get(this LocationProxyComponent self, int type, long key)
{
if (key == 0)
{
throw new Exception("get location key 0");
}
EntityRef<LocationProxyComponent> selfRef = self;
int retryCount = 0;
while (true)
{
self = selfRef;
if (self == null)
{View on GitHub (pinned to 5cab01f7a8)
Solutions
- Call Remove(type, key) without expectedActorId (it passes default) to skip the ownership guard and remove unconditionally.
- Re-query the current ActorId via Get(type, key) before calling Remove with expectedActorId, to avoid stale expectations.
- Wrap cleanup removes in try-catch and suppress the error if the remove is best-effort (the entity is already gone).
- Ensure Remove is not called concurrently with actor migration for the same key.
Example fix
// before await proxy.Remove(type, key, expectedActorId); // throws if ActorId changed // after (unconditional cleanup) await proxy.Remove(type, key); // passes expectedActorId = default, skips guard
Defensive patterns
Strategy: try-catch
Try / catch
// For best-effort cleanup, catch and suppress:
try
{
await proxy.Remove(type, key, expectedActorId);
}
catch (RpcException e)
{
Log.Warning($"location remove failed for {key}, likely already removed: {e.Message}");
// acceptable for cleanup paths
} Prevention
- Use Remove(type, key) without expectedActorId for unconditional cleanup.
- Don't call Remove concurrently with actor migration for the same key.
- For idempotent cleanup, treat remove failures as non-fatal.
When it happens
Trigger: Remove(type, key, expectedActorId) where expectedActorId doesn't match the server's current mapping for that key — another process already changed it. Also fires on server-side database errors or corruption.
Common situations: Calling RemoveLocation after an actor migrated and re-registered with a new ActorId. Race between actor migration and explicit cleanup. RemoveLocation called during server failover when the primary is in an inconsistent state.
Related errors
- location add failed key: {key} actorId: {actorId} error: {re
- location lock failed key: {key} actorId: {actorId} error: {r
- location get failed key: {key} error: {response.Error} messa
- location db manager not found scene: {root.Name}
- ERR_LocationGetRetry
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/719ab141f9a6eb4c.
Report an issue: GitHub.