{"record":{"id":"f80a24b72dd74f2f","repo":"egametang/ET","slug":"location-db-manager-not-found-scene-root-name","errorCode":null,"errorMessage":"location db manager not found scene: {root.Name}","messagePattern":"location db manager not found scene: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationComponentSystem.cs","lineNumber":138,"sourceCode":"                self.RemoveCachedInfo(key);\n                return;\n            }\n\n            LocationInfo locationInfo = self.GetCachedInfo(key) ?? self.CreateInfo(key);\n            locationInfo.TypeStates.Clear();\n            foreach ((int locationType, LocationTypeState state) in snapshot)\n            {\n                locationInfo.TypeStates[locationType] = state;\n            }\n        }\n\n        private static DBComponent GetDBComponent(this LocationComponent self)\n        {\n            Scene root = self.Root();\n            DBManagerComponent dbManagerComponent = root.GetComponent<DBManagerComponent>();\n            if (dbManagerComponent == null)\n            {\n                throw new Exception($\"location db manager not found scene: {root.Name}\");\n            }\n\n            return dbManagerComponent.GetZoneDB(root.Fiber.Zone);\n        }\n\n        private static async ETTask SaveInfoToDB(this LocationComponent self, LocationInfo locationInfo)\n        {\n            if (locationInfo == null)\n            {\n                return;\n            }\n\n            long key = locationInfo.Id;\n            EntityRef<LocationComponent> selfRef = self;\n            EntityRef<LocationInfo> locationInfoRef = locationInfo;\n            DBComponent dbComponent = self.GetDBComponent();\n            EntityRef<DBComponent> dbComponentRef = dbComponent;\n            Scene root = self.Root();","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.actorlocation/Scripts/Hotfix/Server/LocationComponentSystem.cs#L120-L156","documentation":"Thrown by SelectServiceActorIdByRouteKey when the service list passed to route-key selection is null or empty. It is wrapped as RpcException(ERR_ServiceNotFound) so the CallBySceneTypeAsync retry loop (ShouldRetryServiceCallError returns true for ERR_ServiceNotFound) can trigger failover. It is the routing layer's invariant that at least one service instance exists before computing a consistent-hash index via GetRouteIndex.","triggerScenarios":"Calling CallBySceneTypeAsync / ResolveServiceActorIdByRouteKeyOnce when no service of the target sceneType has registered with the ServiceDiscoveryProxy local cache (GetBySceneType returns 0 entries), or when every instance deregistered before the call resolved. ResolveServiceActorIdByRouteKeyOnce already guards Count==0 at line 408, so reaching line 433 means a concurrent mutation emptied the list between the check and SelectServiceActorIdByRouteKey.","commonSituations":"Target provider scene not started yet; service registered under a different sceneType metadata key than the query (SceneTypeSingleton.GetSceneName mismatch); startup race where the consumer calls before the provider registers; wrong zone filter narrowing the result to zero.","solutions":["Ensure the provider scene for that sceneType is started and its registration reached this proxy before consumers call (check OnServiceChangeAddService logs for the sceneName).","Verify the sceneType integer resolves to the same SceneType name on both registration and query via SceneTypeSingleton.Instance.GetSceneName(sceneType).","Raise ServiceResolveRetryTimes / ServiceResolveRetryIntervalMs on the proxy so transient registration races resolve during the built-in retry loop.","Pre-check with GetBySceneType(sceneType) and fall back / queue the request when Count == 0 instead of relying on the exception."],"exampleFix":"// before\nActorId actorId = self.ResolveServiceActorIdByRouteKeyOnce(sceneType, sceneTypeName, routeKey);\n\n// after\nList<ServiceInfo> services = self.GetBySceneType(sceneType);\nif (services == null || services.Count == 0)\n{\n    // defer or fail soft instead of letting routing throw\n    return default;\n}\nActorId actorId = self.ResolveServiceActorIdByRouteKeyOnce(sceneType, sceneTypeName, routeKey);","handlingStrategy":"retry","validationCode":"List<ServiceInfo> services = proxy.GetBySceneType(sceneType);\nif (services == null || services.Count == 0)\n{\n    // provider not registered yet; defer or fall back\n    return;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    T resp = await proxy.CallBySceneTypeAsync<T>(sceneType, request, nameof(request), routeKey);\n}\ncatch (RpcException ex) when (ex.Error == ErrorCode.ERR_ServiceNotFound)\n{\n    // exhaustive retries already attempted by the proxy; surface as service unavailable\n    Log.Warning($\"service not found for sceneType {sceneType}: {ex.Message}\");\n}","preventionTips":["Register provider scenes before starting consumers, and gate consumer start on an OnServiceChangeAddService event for the required sceneType.","Tune ServiceResolveRetryTimes / ServiceResolveRetryIntervalMs to outlast normal startup races.","Always pass the sceneType via the shared SceneType enum so SceneTypeSingleton.GetSceneName resolves identically on both sides."],"tags":["servicediscovery","routing","rpc","startup","failover"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}