{"id":"199881f5101fbf82","repo":"apache/kafka","slug":"cannot-request-fenced-brokers-from-controller-endp","errorCode":null,"errorMessage":"Cannot request fenced brokers from controller endpoint","messagePattern":"Cannot request fenced brokers from controller endpoint","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java","lineNumber":2580,"sourceCode":"\n    @Override\n    public DescribeClusterResult describeCluster(DescribeClusterOptions options) {\n        final KafkaFutureImpl<Collection<Node>> describeClusterFuture = new KafkaFutureImpl<>();\n        final KafkaFutureImpl<Node> controllerFuture = new KafkaFutureImpl<>();\n        final KafkaFutureImpl<String> clusterIdFuture = new KafkaFutureImpl<>();\n        final KafkaFutureImpl<Set<AclOperation>> authorizedOperationsFuture = new KafkaFutureImpl<>();\n\n        final long now = time.milliseconds();\n        runnable.call(new Call(\"listNodes\", calcDeadlineMs(now, options.timeoutMs()),\n            new LeastLoadedBrokerOrActiveKController()) {\n\n            private boolean useMetadataRequest = false;\n\n            @Override\n            AbstractRequest.Builder<?> createRequest(int timeoutMs) {\n                if (!useMetadataRequest) {\n                    if (metadataManager.usingBootstrapControllers() && options.includeFencedBrokers()) {\n                        throw new IllegalArgumentException(\"Cannot request fenced brokers from controller endpoint\");\n                    }\n                    return new DescribeClusterRequest.Builder(new DescribeClusterRequestData()\n                        .setIncludeClusterAuthorizedOperations(options.includeAuthorizedOperations())\n                        .setEndpointType(metadataManager.usingBootstrapControllers() ?\n                            EndpointType.CONTROLLER.id() : EndpointType.BROKER.id())\n                        .setIncludeFencedBrokers(options.includeFencedBrokers()));\n                } else {\n                    // Since this only requests node information, it's safe to pass true for allowAutoTopicCreation (and it\n                    // simplifies communication with older brokers)\n                    return new MetadataRequest.Builder(new MetadataRequestData()\n                        .setTopics(Collections.emptyList())\n                        .setAllowAutoTopicCreation(true)\n                        .setIncludeClusterAuthorizedOperations(\n                            options.includeAuthorizedOperations()));\n                }\n            }\n\n            @Override","sourceCodeStart":2562,"sourceCodeEnd":2598,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java#L2562-L2598","documentation":"Thrown inside the describeCluster Call's createRequest when the Admin client is bootstrapping against KRaft controllers (usingBootstrapControllers() == true) and DescribeClusterOptions.includeFencedBrokers() is true. The controller endpoint does not serve fenced-broker listings — that information is only available from the broker-side DescribeCluster — so requesting it from a controller is rejected with IllegalArgumentException rather than returning incomplete data.","triggerScenarios":"Admin configured with bootstrap.controllers, then calling admin.describeCluster(new DescribeClusterOptions().includeFencedBrokers(true)). The createRequest lambda checks metadataManager.usingBootstrapControllers() && options.includeFencedBrokers() and throws before any RPC is sent.","commonSituations":"Reusing a controller-bootstrapped Admin client for an operational dashboard/health tool that wants to enumerate fenced brokers; code that unconditionally sets includeFencedBrokers(true) on every describeCluster call regardless of bootstrap mode; migrating tooling from broker bootstrap to controller bootstrap without gating the fenced-brokers option.","solutions":["If you need fenced-broker listings, use an Admin client configured with bootstrap.servers (broker endpoint), which supports includeFencedBrokers(true).","If you must keep bootstrap.controllers, drop includeFencedBrokers(true) (leave it false/default) on the describeCluster call.","Gate the option on bootstrap mode: only set includeFencedBrokers(true) when the client is broker-bootstrapped."],"exampleFix":"// before - controller-bootstrapped client + fenced brokers\nprops.put(AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG, \"ctrl1:9093\");\ntry (Admin admin = Admin.create(props)) {\n    admin.describeCluster(new DescribeClusterOptions().includeFencedBrokers(true)) // throws\n        .all().get();\n}\n\n// after - use a broker-bootstrapped client to list fenced brokers\nprops.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, \"broker1:9092\");\ntry (Admin admin = Admin.create(props)) {\n    admin.describeCluster(new DescribeClusterOptions().includeFencedBrokers(true))\n        .all().get();\n}","handlingStrategy":"validation","validationCode":"boolean usingBootstrapControllers = props.containsKey(AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG)\n    && !String.valueOf(props.get(AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG)).isBlank();\nDescribeClusterOptions options = new DescribeClusterOptions();\nif (usingBootstrapControllers) {\n    options.includeFencedBrokers(false); // forced; fenced brokers only via broker endpoint\n}\nadmin.describeCluster(options);","typeGuard":null,"tryCatchPattern":"try {\n    admin.describeCluster(new DescribeClusterOptions().includeFencedBrokers(true));\n} catch (IllegalArgumentException e) {\n    // 'Cannot request fenced brokers from controller endpoint'\n    log.warn(\"includeFencedBrokers requires bootstrap.servers; retrying without it\");\n    admin.describeCluster(new DescribeClusterOptions());\n}","preventionTips":["includeFencedBrokers(true) is only valid when the client reaches brokers (bootstrap.servers); gate it on the bootstrap mode.","If you connected via bootstrap.controllers, never ask for fenced brokers — the controller endpoint does not expose them.","Encapsulate the (bootstrapMode, includeFencedBrokers) pairing in one helper so the two never drift apart."],"tags":["admin-client","kraf","describe-cluster","configuration","argument-validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}