{"record":{"id":"389e058ce7d6bab1","repo":"egametang/ET","slug":"err-actorlocationsendertimeout2","errorCode":"ERR_ActorLocationSenderTimeout2","errorMessage":"{message}","messagePattern":"\\{message\\}","errorType":"error_code","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/MessageLocationSenderComponentSystem.cs","lineNumber":127,"sourceCode":"            EntityRef<Scene> rootRef = root;\n            \n            using (await root.CoroutineLockComponent.Wait(CoroutineLockType.MessageLocationSender, entityId))\n            {\n                messageLocationSender = messageLocationSenderRef;\n                if (messageLocationSender == null)\n                {\n                    throw new RpcException(ErrorCode.ERR_MessageTimeout, $\"{message}\");\n                }\n                \n                if (messageLocationSender.ActorId == default)\n                {\n                    root = rootRef;\n                    self = selfRef;\n                    ActorId actorId = await root.GetComponent<LocationProxyComponent>().Get((int)self.Id, messageLocationSender.Id);\n                    messageLocationSender = messageLocationSenderRef;\n                    if (messageLocationSender == null)\n                    {\n                        throw new RpcException(ErrorCode.ERR_ActorLocationSenderTimeout2, $\"{message}\");\n                    }\n\n                    if (actorId == default)\n                    {\n                        self = selfRef;\n                        self?.Remove(entityId);\n                        throw new RpcException(ErrorCode.ERR_NotFoundActor, $\"{message}\");\n                    }\n\n                    messageLocationSender.ActorId = actorId;\n                }\n                \n                messageLocationSender = messageLocationSenderRef;\n                messageLocationSender.LastSendOrRecvTime = messageLocationSender.GetSingleton<TimeInfo>().ServerNow();\n                root = rootRef;\n                root.GetComponent<MessageSender>().Send(messageLocationSender.ActorId, message);\n            }\n        }","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/MessageLocationSenderComponentSystem.cs#L109-L145","documentation":"In SendInner, the cached ActorId was default, so a LocationProxyComponent.Get was issued to resolve the target. After that async location lookup returned, the MessageLocationSender was re-acquired from EntityRef and found null — the sender was disposed during the location Get round-trip. The message can no longer be delivered through this sender.","triggerScenarios":"MessageLocationSenderOneType.Send(entityId, message) where messageLocationSender.ActorId is default, triggering a location lookup, and during that async lookup the sender is disposed by the Check timer or explicit Remove.","commonSituations":"The Check timer fires during the location server round-trip. Location server is slow, widening the disposal window. Another coroutine removes the sender (e.g., player reconnect) during the lookup.","solutions":["Catch RpcException with ERR_ActorLocationSenderTimeout2 and re-send — GetOrCreate will make a new sender.","Use SendAsync to await and handle disposal errors at the call site.","Reduce location server latency to narrow the disposal window.","Keep the sender's ActorId populated (send frequently) to avoid triggering location lookups."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await senderOneType.SendAsync(entityId, message);\n}\ncatch (RpcException e) when (e.Error == ErrorCode.ERR_ActorLocationSenderTimeout2)\n{\n    // Sender disposed during location lookup — retry recreates it\n    await senderOneType.SendAsync(entityId, message);\n}","preventionTips":["Reduce location server latency to narrow the disposal window.","Keep the sender's ActorId populated to avoid triggering location lookups.","Use SendAsync to handle disposal errors at the call site."],"tags":["message-routing","entity-disposed","location-lookup","fire-and-forget"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}