databendlabs/databend · error
require 1 or 2 addresses in peer str
Error message
require 1 or 2 addresses in peer str: {} What it means
Raised in build_nodes while parsing each entry of the --initial-cluster list. Each peer string must be '<NodeId>=<host>:<port>' with an optional obsolete second gRPC address; this error fires when the address part after '=' does not split into one or two host:port addresses (e.g. empty or extra commas).
Solutions
- Provide at most two comma-separated addresses per peer: '<id>=<addr1>[,<addr2>]'
- Split multi-node clusters into separate peer entries, one per node id
- Remove trailing commas that create empty address tokens
Example fix
// before --initial-cluster 1=a:9191,b:9191,c:9191 // after --initial-cluster 1=a:9191,b:9191 2=c:9191
Defensive patterns
Strategy: validation
Validate before calling
for peer in initial_cluster {
if let Some(addrs) = peer.split('=').nth(1) {
let n = addrs.split(',').filter(|s| !s.is_empty()).count();
if !(1..=2).contains(&n) {
eprintln!("peer {} must have 1 or 2 addresses", peer);
}
}
}
Try / catch
match build_nodes(initial_cluster) {
Err(e) if e.to_string().contains("require 1 or 2 addresses") => eprintln!("one peer entry per node, max 2 addresses each"),
other => other,
} Prevention
- One peer entry per node id; never list the whole cluster on a single line
- Strip trailing commas from generated peer strings
- Generate initial-cluster args from templates rather than typing them
When it happens
Trigger: --initial-cluster peer strings like '1=addr1,addr2,addr3' (3 addresses) or '1=' (empty address list).
Common situations: Listing the whole cluster on one peer line instead of one entry per node; trailing commas creating an empty address; misunderstanding that each node needs its own peer entry.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/9810ec4c49d34237.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/control/src/import.rs:160
///
/// Raw config is: `<NodeId>=<raft-api-host>:<raft-api-port>[,...]`, e.g. `1=localhost:29103` or `1=localhost:29103,0.0.0.0:19191`
/// The second part is obsolete grpc api address and will be just ignored. Databend-meta loads Grpc address from config file when starting up.
fn build_nodes(initial_cluster: Vec<String>, id: u64) -> anyhow::Result<BTreeMap<NodeId, Node>> {
eprintln!("Initialize Cluster: id={}, {:?}", id, initial_cluster);
let mut nodes = BTreeMap::new();
for peer in initial_cluster {
eprintln!("peer:{}", peer);
let id_addrs: Vec<&str> = peer.split('=').collect();
if id_addrs.len() != 2 {
return Err(anyhow::anyhow!("invalid peer str: {}", peer));
}
let id = u64::from_str(id_addrs[0])?;
let addrs: Vec<&str> = id_addrs[1].split(',').collect();
if addrs.len() > 2 || addrs.is_empty() {
return Err(anyhow::anyhow!(
"require 1 or 2 addresses in peer str: {}",
peer
));
}
let url = Url::parse(&format!("http://{}", addrs[0]))?;
let endpoint = match (url.host_str(), url.port()) {
(Some(addr), Some(port)) => Endpoint::new(addr, port),
_ => {
return Err(anyhow::anyhow!("invalid peer raft addr: {}", addrs[0]));
}
};
let node = Node::new(id, endpoint.clone());
eprintln!("new cluster node:{}", node);
nodes.insert(id, node);
}
View on GitHub (pinned to 288d84d76e)