linera-io/linera-protocol · error

Expecting format `(tcp|udp|grpc|grpcs):host:port`

Error message

Expecting format `(tcp|udp|grpc|grpcs):host:port`

What it means

A validator network address string did not split into exactly three ':'-separated parts. ValidatorPublicNetworkPreConfig::from_str parses `protocol:host:port` with a plain split(':'), so anything that is not exactly three segments fails this shape check before protocol or port are even looked at.

Source

Thrown at linera-rpc/src/config.rs:276

            NetworkProtocol::Simple(protocol) => write!(f, "{protocol:?}"),
            NetworkProtocol::Grpc(tls) => match tls {
                TlsConfig::ClearText => write!(f, "grpc"),
                TlsConfig::Tls => write!(f, "grpcs"),
            },
        }
    }
}

impl<P> std::str::FromStr for ValidatorPublicNetworkPreConfig<P>
where
    P: std::str::FromStr,
    P::Err: std::fmt::Display,
{
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts = s.split(':').collect::<Vec<_>>();
        anyhow::ensure!(
            parts.len() == 3,
            "Expecting format `(tcp|udp|grpc|grpcs):host:port`"
        );
        let protocol = parts[0].parse().map_err(|s| anyhow::anyhow!("{s}"))?;
        let host = parts[1].to_owned();
        let port = parts[2].parse()?;
        Ok(ValidatorPublicNetworkPreConfig {
            protocol,
            host,
            port,
        })
    }
}

impl std::str::FromStr for NetworkProtocol {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Rewrite the value as exactly protocol:host:port, e.g. "grpc:validator1.example.com:9000".
  2. Drop "://" from scheme-style URLs — the parser wants "grpc:host:port", not "grpc://host:port".
  3. For IPv6, use a DNS hostname or IPv4 address instead; unbracketed or bracketed literals both fail the split.
  4. Trim stray whitespace/colons when generating the value programmatically.

Example fix

# before: wrong shapes
"grpc://validator1:9000/x"   # extra path segment
"tcp:::1:9000"                # IPv6 literal -> 5 parts
"grpc:validator1"             # missing port

# after: exactly three ':'-separated parts
"grpc:validator1.example.com:9000"
"tcp:10.0.0.1:9000"
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_valid_transport_spec(s: &str) -> bool {
    let mut parts = s.split(':');
    matches!(parts.next(), Some("tcp" | "udp" | "grpc" | "grpcs"))
        && matches!(parts.next(), Some(h) if !h.is_empty() && !h.contains(':'))
        && parts.next().is_some_and(|p| p.parse::<u16>().is_ok())
        && parts.next().is_none()
}

Type guard

fn is_valid_transport_spec(s: &str) -> bool {
    let mut parts = s.split(':');
    matches!(parts.next(), Some("tcp" | "udp" | "grpc" | "grpcs"))
        && matches!(parts.next(), Some(h) if !h.is_empty())
        && parts.next().is_some_and(|p| p.parse::<u16>().is_ok())
        && parts.next().is_none()
}

Prevention

When it happens

Trigger: Missing port ("grpc:validator1"), extra segments ("grpc:host:9000:extra"), URL-style schemes ("grpc://host:9000" keeps 3 parts but "https://host:9000/" does not), and IPv6 literals ("tcp:::1:9000" splits into 5 parts) all produce a segment count != 3.

Common situations: Pasting URLs from browser/RPC docs into validator config; copy-pasting addresses with trailing colons or whitespace; IPv6 hosts, which this parser cannot express because the colons inside the literal break the 3-part split.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/9791daa06dd6d2f6. Report an issue: GitHub.