egametang/ET · error · RpcException
location remove failed key
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.
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
- location get failed key
- location lock failed key
- ERR_LocationGetRetry
- ERR_LocationPrimaryUnavailable
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/719ab141f9a6eb4c.
Report an issue: GitHub.
Appendix: 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)