apache/kafka · error · ConfigException
You must set either bootstrap.servers or bootstrap.controlle
Error message
You must set either bootstrap.servers or bootstrap.controllers
What it means
Thrown by KafkaAdminClient.determineBootstrapType during AdminClient creation when neither bootstrap.servers nor bootstrap.controllers is present in the configuration. The admin client requires exactly one bootstrap source so the NetworkClient can resolve an initial node and seed metadata; with both lists empty there is no entry point to the cluster, so construction fails fast with a ConfigException rather than silently producing a non-functional client.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java:541
* Validates that exactly one of bootstrap.servers or bootstrap.controllers is configured.
*
* @param config The admin client configuration
* @return true if using bootstrap.controllers, false if using bootstrap.servers
* @throws ConfigException if both or neither bootstrap configurations are set
*/
static boolean determineBootstrapType(AdminClientConfig config) {
List<String> bootstrapServers = config.getList(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG);
if (bootstrapServers == null) {
bootstrapServers = Collections.emptyList();
}
List<String> controllerServers = config.getList(AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG);
if (controllerServers == null) {
controllerServers = Collections.emptyList();
}
if (bootstrapServers.isEmpty()) {
if (controllerServers.isEmpty()) {
throw new ConfigException("You must set either " +
CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG + " or " +
AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG);
} else {
return true; // Using bootstrap.controllers
}
} else {
if (controllerServers.isEmpty()) {
return false; // Using bootstrap.servers
} else {
throw new ConfigException("You cannot set both " +
CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG + " and " +
AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG);
}
}
}
static KafkaAdminClient createInternal(AdminClientConfig config, TimeoutProcessorFactory timeoutProcessorFactory) {
return createInternal(config, timeoutProcessorFactory, null);View on GitHub (pinned to c31c9215e1)
Solutions
- Add bootstrap.servers=<host:port,...> to the Admin config map/properties (the legacy, universally-supported option).
- If targeting a KRaft cluster directly, set bootstrap.controllers=<controllerHost:port,...> instead.
- Verify the property key spelling is exactly bootstrap.servers (or bootstrap.controllers) and that the value resolves to a non-empty string before calling Admin.create.
- Log the resolved config right before Admin.create so a missing/mistyped key is visible at startup.
Example fix
// before Properties p = new Properties(); p.put(AdminClientConfig.CLIENT_ID_CONFIG, "myAdmin"); Admin admin = Admin.create(p); // throws ConfigException // after Properties p = new Properties(); p.put(AdminClientConfig.CLIENT_ID_CONFIG, "myAdmin"); p.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, "broker1:9092,broker2:9092"); Admin admin = Admin.create(p);
Defensive patterns
Strategy: validation
Validate before calling
boolean hasServers = props.containsKey(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG)
&& !String.valueOf(props.get(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG)).isBlank();
boolean hasControllers = props.containsKey(AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG)
&& !String.valueOf(props.get(AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG)).isBlank();
if (!hasServers && !hasControllers) {
throw new IllegalArgumentException("Set exactly one of bootstrap.servers or bootstrap.controllers");
}
Admin admin = Admin.create(props); Try / catch
try {
Admin admin = Admin.create(props);
} catch (ConfigException e) {
// 'You must set either bootstrap.servers or bootstrap.controllers'
log.error("Missing bootstrap config", e);
} Prevention
- Centralize broker/controller endpoint resolution in a single config builder so every Admin creation site sets exactly one bootstrap property.
- Fail fast at application startup with a config validation step rather than letting Admin.create throw.
- Prefer bootstrap.servers for broker-facing admin tasks; use bootstrap.controllers only when talking directly to KRaft controllers.
When it happens
Trigger: Calling Admin.create(Properties)/Admin.create(Map) with a config map that omits both CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG ("bootstrap.servers") and AdminClientConfig.BOOTSTRAP_CONTROLLERS_CONFIG ("bootstrap.controllers"); or passing an empty string for bootstrap.servers (which config.getList parses into an empty list).
Common situations: Config loaded from a properties file where the bootstrap.servers line was commented out, mistyped (e.g. "bootstrap.serverss"), or overridden to empty by an environment variable; Spring/Quarkus injection that left the property unresolved (literal ${kafka.bootstrap.servers}); code that builds the config map dynamically and the source list came back null.
Related errors
- You cannot set both bootstrap.servers and bootstrap.controll
- Failed to create new KafkaAdminClient
- The specified value of default.api.timeout.ms must be no sma
- There are no nodes in the Kafka cluster
- Expected response from CONTROLLER endpoint, but got response
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/bbddb220f8535b5f.json.
Report an issue: GitHub.