{"record":{"id":"ea7ad6de2b4e253c","repo":"egametang/ET","slug":"err-locationgetretry","errorCode":"ERR_LocationGetRetry","errorMessage":"location get retry type: {locationType} key: {key} actorId: {state.ActorId} lockToken: {state.LockToken}","messagePattern":"location get retry type: (.+?) key: (.+?) actorId: (.+?) lockToken: (.+?)","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"warning","filePath":"Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationComponentSystem.cs","lineNumber":600,"sourceCode":"\n                    try\n                    {\n                        await self.SaveInfoToDB(locationInfo);\n                    }\n                    catch\n                    {\n                        self = selfRef;\n                        if (self != null)\n                        {\n                            self.RestoreStates(key, snapshot);\n                        }\n\n                        throw;\n                    }\n                }\n                else if (IsLocked(state))\n                {\n                    throw new RpcException(ErrorCode.ERR_LocationGetRetry,\n                        $\"location get retry type: {locationType} key: {key} actorId: {state.ActorId} lockToken: {state.LockToken}\");\n                }\n\n                Log.Info($\"location get type: {locationType} key: {key} actorId: {state.ActorId}\");\n                return state.ActorId;\n            }\n        }\n\n        public static void RefreshPrimaryState(this LocationComponent self)\n        {\n            Scene root = self.Root();\n            if (root == null)\n            {\n                return;\n            }\n\n            ServiceDiscoveryProxy serviceDiscoveryProxy = root.GetComponent<ServiceDiscoveryProxy>();\n            if (serviceDiscoveryProxy == null)","sourceCodeStart":582,"sourceCodeEnd":618,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationComponentSystem.cs#L582-L618","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use LocationProxyComponent.Get which automatically retries on ERR_LocationGetRetry up to 20 times (configurable via locationRequestRetryTimes) with increasing delay.","If retries are exhausted, increase locationRequestRetryTimes or locationRequestRetryIntervalMs on the LocationProxyComponent.","Ensure locks are released promptly -- check for leaked locks from crashed processes.","If using time=0 locks, switch to finite-time locks so they auto-expire and unblock Get."],"exampleFix":"// before -- direct Get on LocationComponent, no retry\nActorId id = await locationComponent.Get(type, key);\n\n// after -- proxy Get with built-in retry\nActorId id = await locationProxy.Get(type, key);","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// LocationProxyComponent.Get already retries ERR_LocationGetRetry internally.\n// If you call LocationComponent.Get directly, wrap with retry:\nfor (int i = 0; i < maxRetries; i++)\n{\n    try { return await locationComponent.Get(type, key); }\n    catch (RpcException e) when (e.Error == ErrorCode.ERR_LocationGetRetry && i < maxRetries - 1)\n    {\n        await root.TimerComponent.WaitAsync(100 * (i + 1));\n    }\n}","preventionTips":["Always use LocationProxyComponent.Get instead of LocationComponent.Get -- it has built-in retry logic.","Keep locks short-lived to minimize Get contention.","Tune locationRequestRetryTimes and locationRequestRetryIntervalMs based on expected lock duration."],"tags":["location","lock","retry","get","transient"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}