{"record":{"id":"6e5495ba046e89b1","repo":"egametang/ET","slug":"location-add-failed-key-key-actorid-actorid","errorCode":null,"errorMessage":"location add failed key: {key} actorId: {actorId} error: {response.Message}","messagePattern":"location add failed key: (.+?) actorId: (.+?) error: (.+?)","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationProxyComponentSystem.cs","lineNumber":216,"sourceCode":"                    {\n                        throw new Exception(\"location proxy root disposed\");\n                    }\n                }\n            }\n        }\n\n        public static async ETTask Add(this LocationProxyComponent self, int type, long key, ActorId actorId)\n        {\n            Log.Info($\"location proxy add {key}, {actorId} {self.GetSingleton<TimeInfo>().ServerNow()}\");\n            ObjectAddRequest request = ObjectAddRequest.Create();\n            request.Type = type;\n            request.Key = key;\n            request.ActorId = actorId;\n\n            ObjectAddResponse response = (ObjectAddResponse)await self.CallPrimaryWithRetry(key, request);\n            if (response.Error != ErrorCode.ERR_Success)\n            {\n                throw new RpcException(response.Error,\n                    $\"location add failed key: {key} actorId: {actorId} error: {response.Message}\");\n            }\n        }\n\n        public static async ETTask<long> LockWithToken(this LocationProxyComponent self, int type, long key, ActorId actorId,\n            int time = 60000)\n        {\n            Log.Info($\"location proxy lock {key}, {actorId} {self.GetSingleton<TimeInfo>().ServerNow()}\");\n\n            ObjectLockRequest request = ObjectLockRequest.Create();\n            request.Type = type;\n            request.Key = key;\n            request.ActorId = actorId;\n            request.Time = time;\n\n            ObjectLockResponse response = (ObjectLockResponse)await self.CallPrimaryWithRetry(key, request);\n            if (response.Error != ErrorCode.ERR_Success)\n            {","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationProxyComponentSystem.cs#L198-L234","documentation":"Thrown by LocationProxyComponent.Add when the RPC response from the primary Location scene returns a non-success error code. This is a wrapper exception that re-throws the server-side error code with additional proxy-level context (key and actorId). The actual root cause is in response.Error / response.Message, which could be any of the server-side errors (ERR_LocationAlreadyLocked, ERR_LocationFollowerRejected, etc.).","triggerScenarios":"LocationProxyComponent.Add(type, key, actorId) calls CallPrimaryWithRetry, gets a response with response.Error != ERR_Success. CallPrimaryWithRetry already retried up to locationRequestRetryTimes for transient errors (FollowerRejected, PrimaryUnavailable), so this throw means either retries were exhausted or the error is non-transient (e.g. AlreadyLocked).","commonSituations":"The primary returned ERR_LocationAlreadyLocked (the key is locked); retries exhausted during a primary failover (all 20 retries hit PrimaryUnavailable/FollowerRejected); the primary returned an unexpected internal error.","solutions":["Catch RpcException and inspect e.Error to determine the root cause -- ERR_LocationAlreadyLocked means the key is locked, ERR_LocationPrimaryUnavailable means no primary was reachable after retries.","For ERR_LocationAlreadyLocked, resolve the lock conflict before retrying Add.","For ERR_LocationPrimaryUnavailable/ERR_LocationFollowerRejected after exhaustion, check Location scene availability and topology.","Increase locationRequestRetryTimes if transient failures are expected to last longer."],"exampleFix":"// before -- unhandled proxy Add\nawait locationProxy.Add(type, key, actorId);\n\n// after -- catch and handle by error code\ntry\n{\n    await locationProxy.Add(type, key, actorId);\n}\ncatch (RpcException e) when (e.Error == ErrorCode.ERR_LocationAlreadyLocked)\n{\n    Log.Warning($\"location add blocked by lock: key={key}\");\n}\ncatch (RpcException e) when (e.Error == ErrorCode.ERR_LocationPrimaryUnavailable)\n{\n    Log.Error($\"location primary unavailable after retries: key={key}\");\n    throw;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await locationProxy.Add(type, key, actorId);\n}\ncatch (RpcException e) when (e.Error == ErrorCode.ERR_LocationAlreadyLocked)\n{\n    Log.Warning($\"Add rejected -- key {key} is locked\");\n}\ncatch (RpcException e) when (e.Error == ErrorCode.ERR_LocationPrimaryUnavailable)\n{\n    Log.Error($\"Location primary unavailable after retries: {e.Message}\");\n    throw;\n}","preventionTips":["Always catch RpcException from proxy Add and inspect e.Error for the specific root cause.","Differentiate transient errors (PrimaryUnavailable, FollowerRejected -- already retried) from logical errors (AlreadyLocked -- requires resolution).","Log the full exception including response.Message for diagnosis."],"tags":["location","proxy","rpc","wrapper","add"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}