databendlabs/databend · error
invalid peer str
Error message
invalid peer str: {} What it means
When building initial-cluster nodes for import, build_nodes parses each peer string expected as '<id>=<addr1>[,addr2]'. A peer string that does not split into exactly two '='-separated parts is rejected with 'invalid peer str: {}'.
Solutions
- Format each peer as '<node-id>=<grpc-addr>[,<grpc-addr2>]', e.g. '1=127.0.0.1:9191'
- Check for stray '=' characters or missing address parts and re-quote the argument in the shell
- Count entries: the id must be a u64 before the '=' and an address after
Example fix
// before --initial-cluster 1=127.0.0.1 2=127.0.0.1 // after --initial-cluster 1=127.0.0.1:9191 2=127.0.0.1:29191
Defensive patterns
Strategy: validation
Validate before calling
for peer in initial_cluster {
if peer.split('=').count() != 2 {
eprintln!("invalid peer str: {} (expected <id>=<addr>[,addr2])", peer);
}
}
Try / catch
match build_nodes(initial_cluster) {
Err(e) if e.to_string().starts_with("invalid peer str") => eprintln!("fix peer format: id=addr1[,addr2]"),
other => other,
} Prevention
- Quote --initial-cluster arguments in shell to protect '=' and ','
- Validate peer strings with a dry-run or echo before invoking metactl
- Use consistent id=host:port naming per node
When it happens
Trigger: Passing --initial-cluster entries missing '=' or containing multiple '=' characters, e.g. '1=127.0.0.1' is fine but '1' or 'a=b=c' fails.
Common situations: Hand-typing the initial cluster spec; copy-paste errors; shell quoting mangling commas or equals; empty peer entries.
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/ec8e7b5777050966.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/control/src/import.rs:154
eprintln!("Finished import, max_log_id: '{}'", max_log_id.display());
Ok(max_log_id)
}
/// Build `Node` for cluster with new addresses configured.
///
/// 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]));
}
};
View on GitHub (pinned to 288d84d76e)