{"record":{"id":"327cf72411fffbc2","repo":"apache/pulsar","slug":"unable-to-determine-latest-version-since-broker-ve","errorCode":null,"errorMessage":"Unable to determine latest version since broker version map was empty","messagePattern":"Unable to determine latest version since broker version map was empty","errorType":"exception","errorClass":"BrokerFilterBadVersionException","httpStatus":null,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/loadbalance/extensions/filter/BrokerVersionFilter.java","lineNumber":111,"sourceCode":"        return CompletableFuture.completedFuture(brokers);\n    }\n\n    /**\n     * Get the most recent broker version number from the broker lookup data of all the running brokers.\n     * The version number is from the build artifact in the pom and got added to the package when it was built by Maven\n     *\n     * @param brokerMap\n     *             The BrokerId -> BrokerLookupData Map.\n     * @return The most recent broker version\n     * @throws BrokerFilterBadVersionException\n     *            If the most recent version is undefined (e.g., a bad broker version was encountered or a broker\n     *            does not have a version string in its lookup data.\n     */\n    public Version getLatestVersionNumber(Map<String, BrokerLookupData> brokerMap)\n            throws BrokerFilterBadVersionException {\n\n        if (brokerMap.size() == 0) {\n            throw new BrokerFilterBadVersionException(\n                    \"Unable to determine latest version since broker version map was empty\");\n        }\n\n        Version latestVersion = null;\n        for (Map.Entry<String, BrokerLookupData> entry : brokerMap.entrySet()) {\n            String brokerId = entry.getKey();\n            String version = entry.getValue().brokerVersion();\n            if (null == version || version.length() == 0) {\n                log.warn().attr(\"broker\", brokerId)\n                        .log(\"No version string in lookup data for broker; disabling PreferLaterVersions feature\");\n                // Trigger the load manager to reset all the brokers to the original set\n                throw new BrokerFilterBadVersionException(\"No version string in lookup data for broker \\\"\"\n                        + brokerId + \"\\\"\");\n            }\n            Version brokerVersionVersion;\n            try {\n                brokerVersionVersion = Version.valueOf(version);\n            } catch (Exception x) {","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/loadbalance/extensions/filter/BrokerVersionFilter.java#L93-L129","documentation":"BrokerVersionFilter.getLatestVersionNumber scans the map of candidate brokers to find the newest broker version (semver via java-semver, build-aware ordering). If the map is empty there is no version to compare, so it throws BrokerFilterBadVersionException. In filterAsync this failure causes the PreferLaterVersions filtering step to fail, forcing the load manager to fall back to the full unfiltered broker set.","triggerScenarios":"filterAsync is invoked with an empty candidate broker map while loadBalancerBrokerFilterNames includes broker_version_filter and preferLaterVersions=true; getLatestVersionNumber is also called directly with an empty map.","commonSituations":"All brokers have been filtered out by earlier BrokerFilters in the chain, no brokers are registered in the load-data store (fresh cluster, metadata connectivity problems), or a custom filter upstream removed every candidate.","solutions":["Check that other broker filters are not removing all candidates before broker_version_filter runs (review loadBalancerBrokerFilterNames order).","Verify brokers are actually reporting load data to the metadata store and that the ExtensibleLoadManager has a non-empty available-broker map.","Set preferLaterVersions=false or remove broker_version_filter from loadBalancerBrokerFilterNames if version-based filtering is not needed.","If calling getLatestVersionNumber programmatically, guard brokerMap.isEmpty() before invoking."],"exampleFix":"// before\nVersion latest = filter.getLatestVersionNumber(brokers);\n// after\nif (brokers.isEmpty()) {\n    return CompletableFuture.completedFuture(brokers); // let load manager handle empty set\n}\nVersion latest = filter.getLatestVersionNumber(brokers);","handlingStrategy":"validation","validationCode":"if (brokers == null || brokers.isEmpty()) {\n    return CompletableFuture.completedFuture(brokers); // skip version filter\n}\nreturn filter.filterAsync(brokers, serviceUnit, context);","typeGuard":null,"tryCatchPattern":"try {\n    Version latest = filter.getLatestVersionNumber(brokerMap);\n} catch (BrokerFilterBadVersionException e) {\n    log.warn(\"Version filter disabled: {}\", e.getMessage());\n    // fall back to unfiltered broker set\n}","preventionTips":["Never chain broker_version_filter after filters that can return an empty set without an emptiness guard.","Alert on empty available-broker sets in the load manager registry.","Keep preferLaterVersions=false unless the cluster guarantees all brokers report versions."],"tags":["load-manager","broker-filter","version-comparison","empty-collection"],"backgroundTag":"empty-candidate-broker-set","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}