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
- Rewrite the value as exactly protocol:host:port, e.g. "grpc:validator1.example.com:9000".
- Drop "://" from scheme-style URLs — the parser wants "grpc:host:port", not "grpc://host:port".
- For IPv6, use a DNS hostname or IPv4 address instead; unbracketed or bracketed literals both fail the split.
- 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
- Generate validator addresses as format!("{protocol}:{host}:{port}") instead of string concatenation.
- Remember this format cannot express IPv6 literals — use hostnames.
- Validate specs in config-loading code so errors surface with file/line context.
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
- {s}
- Validator spec must be in format: public_key,account_key,add
- TLS not supported between proxy and shards.
- We should have one genesis config path and one optional name
- For Storage service, the formatting has to be service:endpoi
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/9791daa06dd6d2f6.
Report an issue: GitHub.