{"record":{"id":"3102ea4ab303ffb3","repo":"apache/kafka","slug":"metadata-fetch-failed-due-to-missing-broker-list","errorCode":null,"errorMessage":"Metadata fetch failed due to missing broker list","messagePattern":"Metadata fetch failed due to missing broker list","errorType":"exception","errorClass":"StaleMetadataException","httpStatus":null,"severity":"warning","filePath":"clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java","lineNumber":3594,"sourceCode":"    @Override\n    public ListGroupsResult listGroups(ListGroupsOptions options) {\n        final KafkaFutureImpl<Collection<Object>> all = new KafkaFutureImpl<>();\n        final long nowMetadata = time.milliseconds();\n        final long deadline = calcDeadlineMs(nowMetadata, options.timeoutMs());\n        runnable.call(new Call(\"findAllBrokers\", deadline, new LeastLoadedNodeProvider()) {\n            @Override\n            MetadataRequest.Builder createRequest(int timeoutMs) {\n                return new MetadataRequest.Builder(new MetadataRequestData()\n                    .setTopics(Collections.emptyList())\n                    .setAllowAutoTopicCreation(true));\n            }\n\n            @Override\n            void handleResponse(AbstractResponse abstractResponse) {\n                MetadataResponse metadataResponse = (MetadataResponse) abstractResponse;\n                Collection<Node> nodes = metadataResponse.brokers();\n                if (nodes.isEmpty())\n                    throw new StaleMetadataException(\"Metadata fetch failed due to missing broker list\");\n\n                HashSet<Node> allNodes = new HashSet<>(nodes);\n                final ListGroupsResults results = new ListGroupsResults(allNodes, all);\n\n                for (final Node node : allNodes) {\n                    final long nowList = time.milliseconds();\n                    runnable.call(new Call(\"listGroups\", deadline, new ConstantNodeIdProvider(node.id())) {\n                        @Override\n                        ListGroupsRequest.Builder createRequest(int timeoutMs) {\n                            List<String> groupTypes = options.types()\n                                .stream()\n                                .map(GroupType::toString)\n                                .collect(Collectors.toList());\n                            List<String> groupStates = options.groupStates()\n                                .stream()\n                                .map(GroupState::toString)\n                                .collect(Collectors.toList());\n                            return new ListGroupsRequest.Builder(new ListGroupsRequestData()","sourceCodeStart":3576,"sourceCodeEnd":3612,"githubUrl":"https://github.com/apache/kafka/blob/996fb4585aa1bcc8980b0e1b8d6b168b986cd979/clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java#L3576-L3612","documentation":"A StaleMetadataException thrown while handling a MetadataResponse during listGroups: the response carried an empty broker list. The client treats this as stale metadata so the Call machinery can retry against fresh metadata. It is a retryable signal, not a hard failure.","triggerScenarios":"listGroups (or listConsumerGroups/listConsumerGroupOffsets that fans out to nodes) issues an empty-topic MetadataRequest, and the response.brokers() collection is empty. Typical of a cluster that is starting up, mid-rebalance, or temporarily unreachable.","commonSituations":"Calling listGroups immediately after bringing a cluster up before brokers register; network partition where the contacted node has no peer info; a misconfigured broker with no advertised.listeners; during controlled shutdown windows.","solutions":["Let the Admin client retry: StaleMetadataException is designed to trigger Call retries, so ensure retries are not disabled and the overall timeout allows a few attempts.","If it persists, verify the cluster is healthy (brokers up, advertised.listeners correct, controller elected).","Retry the listGroups operation after a short delay once metadata has refreshed."],"exampleFix":"// before (single attempt, no retry budget)\nListGroupsOptions opts = new ListGroupsOptions().timeoutMs(2000);\nadmin.listGroups(opts).all().get();\n\n// after (allow retries + longer deadline)\nListGroupsOptions opts = new ListGroupsOptions().timeoutMs(30000);\nadmin.listGroups(opts).all().get();","handlingStrategy":"retry","validationCode":"// ensure retry budget and deadline allow recovery\nListGroupsOptions opts = new ListGroupsOptions().timeoutMs(60_000);\n// retries are handled by the Call framework; do not disable them","typeGuard":null,"tryCatchPattern":"// StaleMetadataException is retryable; let KafkaFuture retries handle it,\n// then retry the top-level operation if it still fails.\ntry {\n    admin.listGroups(opts).all().get();\n} catch (ExecutionException e) {\n    if (e.getCause() instanceof StaleMetadataException) {\n        // wait for metadata refresh, then retry admin.listGroups\n    }\n}","preventionTips":["Give listGroups an adequate timeout so retries can succeed.","Verify cluster health (broker count, advertised.listeners) if the error persists."],"tags":["kafka-admin","list-groups","metadata","retryable","cluster-health"],"backgroundTag":null,"analyzedSha":"996fb4585aa1bcc8980b0e1b8d6b168b986cd979","analyzedAt":"2026-08-11T22:03:28.655Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}