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

  1. Format each peer as '<node-id>=<grpc-addr>[,<grpc-addr2>]', e.g. '1=127.0.0.1:9191'
  2. Check for stray '=' characters or missing address parts and re-quote the argument in the shell
  3. 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

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)