{"record":{"id":"73fe5b4c989cda8b","repo":"egametang/ET","slug":"service-discovery-endpoint-unavailable-after-resol","errorCode":null,"errorMessage":"service discovery endpoint unavailable after resolve, request: {requestName}, scene: {self.Root().Name}","messagePattern":"service discovery endpoint unavailable after resolve, request: (.+?), scene: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.servicediscovery/Scripts/Hotfix/Server/ServiceDiscoveryAgentSystem.cs","lineNumber":608,"sourceCode":"            {\n                self = selfRef;\n                if (self == null)\n                {\n                    throw new Exception(\"service discovery agent disposed\");\n                }\n\n                if (self.ServiceDiscoveryActorId == default)\n                {\n                    await self.EnsureReadyForRequestAsync(requestName);\n                    self = selfRef;\n                    if (self == null)\n                    {\n                        throw new Exception(\"service discovery agent disposed\");\n                    }\n\n                    if (!self.IsReady() || self.ServiceDiscoveryActorId == default)\n                    {\n                        throw new Exception(\n                            $\"service discovery endpoint unavailable after resolve, request: {requestName}, scene: {self.Root().Name}\");\n                    }\n\n                    continue;\n                }\n\n                ActorId targetActorId = self.ServiceDiscoveryActorId;\n                try\n                {\n                    IResponse rawResponse = await self.MessageSender.Call(targetActorId, request);\n                    self = selfRef;\n                    if (self == null)\n                    {\n                        throw new Exception(\"service discovery agent disposed\");\n                    }\n\n                    if (rawResponse is not T response)\n                    {","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.servicediscovery/Scripts/Hotfix/Server/ServiceDiscoveryAgentSystem.cs#L590-L626","documentation":"Thrown at line 608 in ForwardToDiscoveryByFailoverCore: EnsureReadyForRequestAsync returned without throwing (so the agent is alive and considered ready) yet ServiceDiscoveryActorId is still default or IsReady() is false. This is an inconsistent-state failure — the readiness machinery believes resolution succeeded but no concrete master endpoint was populated, so there is nowhere to send the request.","triggerScenarios":"EnsureReadyForRequestAsync completed (agent alive, retries OK) but the endpoint field was cleared between the ensure call and the check (e.g. InvalidateEndpointAndTriggerBackgroundRegister ran concurrently), or IsReady()'s definition (ServiceDiscoveryActorId != default AND AgentRegistered) is partially satisfied. Also reachable if SwitchToEndpoint never set the actor id.","commonSituations":"Concurrent endpoint invalidation racing with a ready check; a master that flaps (registers then immediately drops) so the agent flips between ready and not; a bug where registration sets AgentRegistered but ServiceDiscoveryActorId stays default.","solutions":["Eliminate concurrent endpoint mutation during a request: serialize invalidation and forwarding.","Re-trigger registration and retry the request once at the caller level when this specific message appears.","Audit SwitchToEndpoint / registration to confirm ServiceDiscoveryActorId and AgentRegistered status are set atomically."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if (agent.ServiceDiscoveryActorId == default || !agent.IsReady())\n{\n    // inconsistent ready state; do not forward\n}","typeGuard":null,"tryCatchPattern":"catch (Exception e) when (e.Message.Contains(\"endpoint unavailable after resolve\"))\n{\n    // retry once after triggering re-register\n    agent?.InvalidateEndpointAndTriggerBackgroundRegister(\"caller-retry\");\n}","preventionTips":["Ensure ServiceDiscoveryActorId and AgentRegistered are set atomically during registration.","Serialize endpoint mutation with request forwarding.","Monitor for endpoint flapping."],"tags":["csharp","et-framework","service-discovery","concurrency","master-election","rpc"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}