{"record":{"id":"e16aeecf418c0968","repo":"apache/pulsar","slug":"no-latest-service-lookup-data-found","errorCode":null,"errorMessage":"No latest service lookup data found.","messagePattern":"No latest service lookup data found\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/loadbalance/extensions/manager/RedirectManagerForLoadManagerMigration.java","lineNumber":117,"sourceCode":"        boolean debug = ExtensibleLoadManagerImpl.debug(pulsar.getConfiguration(), log);\n        return getAvailableBrokerLookupDataAsync().thenApply(lookupDataMap -> {\n            if (lookupDataMap.isEmpty()) {\n                String errorMsg = \"No available broker found.\";\n                log.warn(errorMsg);\n                throw new IllegalStateException(errorMsg);\n            }\n            AtomicReference<BrokerLookupData> latestServiceLookupData = new AtomicReference<>();\n            AtomicLong lastStartTimestamp = new AtomicLong(0L);\n            lookupDataMap.forEach((key, value) -> {\n                if (lastStartTimestamp.get() <= value.getStartTimestamp()) {\n                    lastStartTimestamp.set(value.getStartTimestamp());\n                    latestServiceLookupData.set(value);\n                }\n            });\n            if (latestServiceLookupData.get() == null) {\n                String errorMsg = \"No latest service lookup data found.\";\n                log.warn(errorMsg);\n                throw new IllegalStateException(errorMsg);\n            }\n\n            if (Objects.equals(latestServiceLookupData.get().getLoadManagerClassName(), currentLMClassName)) {\n                if (debug) {\n                    log.info().attr(\"name\", currentLMClassName)\n                            .log(\"No need to redirect, current load manager class name\");\n                }\n                return Optional.empty();\n            }\n            var serviceLookupDataObj = latestServiceLookupData.get();\n            var candidateBrokers = new ArrayList<BrokerLookupData>();\n            lookupDataMap.forEach((key, value) -> {\n                if (Objects.equals(value.getLoadManagerClassName(), serviceLookupDataObj.getLoadManagerClassName())) {\n                    candidateBrokers.add(value);\n                }\n            });\n            var selectedBroker = candidateBrokers.get((int) (Math.random() * candidateBrokers.size()));\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/loadbalance/extensions/manager/RedirectManagerForLoadManagerMigration.java#L99-L135","documentation":"After collecting available brokers, redirectIfLoadBalancerOnBrokerIsNotExpected picks the broker with the latest start timestamp as the 'latest service'. If no entry won (map non-empty but no data set, defensive case), the future fails with IllegalStateException 'No latest service lookup data found.'","triggerScenarios":"getAvailableBrokerLookupDataAsync returned a non-empty map but the forEach never set latestServiceLookupData — only possible with pathological lookup data (e.g. negative/NaN-like start timestamps never satisfying lastStartTimestamp <= value.getStartTimestamp() for a first negative value... in practice the initial 0L is overwritten by any timestamp >= 0, so this fires only when the map was emptied concurrently or timestamps are negative).","commonSituations":"Race where the broker registry is emptied between the emptiness check and the iteration, or corrupted start timestamps in broker lookup data; mostly seen in tests stubbing lookup data with negative start timestamps.","solutions":["Verify broker lookup data has sane non-negative start timestamps; re-register/restart brokers with bad data.","Re-check metadata-store connectivity — a concurrent deregistration of all brokers can empty the map mid-flight.","Retry the lookup; this is usually transient.","In tests, ensure stubbed BrokerLookupData has startTimestamp >= 0."],"exampleFix":"// before (test)\nnew BrokerLookupData(...).setStartTimestamp(-1);\n// after\nnew BrokerLookupData(...).setStartTimestamp(System.currentTimeMillis());","handlingStrategy":"retry","validationCode":"if (lookupDataMap.isEmpty()) throw new RestException(Response.Status.SERVICE_UNAVAILABLE, \"no brokers\");\nboolean anyValid = lookupDataMap.values().stream()\n    .anyMatch(d -> d.getStartTimestamp() >= 0);\nif (!anyValid) throw new RestException(Response.Status.SERVICE_UNAVAILABLE, \"invalid lookup data\");","typeGuard":null,"tryCatchPattern":"CompletableFuture.supplyAsync(() -> redirectIfLoadBalancerOnBrokerIsNotExpected(...))\n  .orTimeout(3, TimeUnit.SECONDS)\n  .exceptionally(ex -> { /* retry lookup once, then 503 */ return null; });","preventionTips":["Ensure broker lookup data always has non-negative start timestamps.","Treat empty/volatile broker registries as transient and retry with bounded backoff.","Watch for metadata-store watch storms that empty snapshots mid-read."],"tags":["load-manager","redirect","race-condition","lookup-data"],"backgroundTag":"no-broker-available","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}