linera-io/linera-protocol · error
Invalid address to connect to
Error message
Invalid address to connect to
What it means
TransportProtocol::connect (linera-rpc/src/simple/transport.rs:150) resolves the given address with tokio's lookup_host and expects success before connecting. lookup_host fails when the address string is malformed (no port, non-numeric port, invalid characters) or DNS resolution fails (unknown host, resolver unreachable). Although connect returns io::Result, this resolution step panics instead of returning the error, so a bad simple-network address crashes the caller (used by new, open_in_memory, subscribe_to_shards, try_proxy_message, and the net proxy main).
Source
Thrown at linera-rpc/src/simple/transport.rs:156
pub trait Transport:
Stream<Item = Result<RpcMessage, codec::Error>> + Sink<RpcMessage, Error = codec::Error>
{
}
impl<T> Transport for T where
T: Stream<Item = Result<RpcMessage, codec::Error>> + Sink<RpcMessage, Error = codec::Error>
{
}
impl TransportProtocol {
/// Creates a transport for this protocol.
pub async fn connect(
self,
address: impl ToSocketAddrs,
) -> Result<impl Transport, std::io::Error> {
let mut addresses = lookup_host(address)
.await
.expect("Invalid address to connect to");
let address = addresses
.next()
.expect("Couldn't resolve address to connect to");
let stream: futures::future::Either<_, _> = match self {
TransportProtocol::Udp => {
let socket = UdpSocket::bind(&"0.0.0.0:0").await?;
UdpFramed::new(socket, Codec)
.with(move |message| future::ready(Ok((message, address))))
.map_ok(|(message, _address)| message)
.left_stream()
}
TransportProtocol::Tcp => {
let stream = TcpStream::connect(address).await?;
Framed::new(stream, Codec).right_stream()
}View on GitHub (pinned to 6c226ddcb3)
Solutions
- Use an explicit 'host:port' string with a numeric port, e.g. 'localhost:9521' or '10.0.0.1:9521'.
- Prefer IP literals in DNS-less environments (containers, test clusters).
- Verify resolution outside the app: `getent hosts <host>` or `nslookup <host>`.
- If embedding, validate addresses up front with tokio::net::lookup_host before calling connect.
Example fix
// before
let transport = TransportProtocol::Tcp.connect("validator").await?; // no port -> panic
// after
let transport = TransportProtocol::Tcp.connect("validator:9521").await?;
// when embedding, validate first
if tokio::net::lookup_host((host.as_str(), port)).await.is_err() {
return Err(anyhow::anyhow!("cannot resolve {host}:{port}"));
} Defensive patterns
Strategy: validation
Validate before calling
// Validate host:port resolution before calling connect:
async fn resolvable(addr: &str) -> bool {
tokio::net::lookup_host(addr.to_string()).await.map(|mut s| s.next().is_some()).unwrap_or(false)
}
if !resolvable(&peer_address).await {
anyhow::bail!("address '{peer_address}' is malformed or unresolvable; use host:port with a numeric port");
} Type guard
fn is_host_port(s: &str) -> bool {
s.parse::<std::net::SocketAddr>().is_ok()
|| s.rsplit_once(':').map(|(h, p)| !h.is_empty() && p.parse::<u16>().is_ok()).unwrap_or(false)
} Try / catch
// The library panics during resolution despite returning io::Result; wrap with catch_unwind when embedding:
let outcome = std::panic::catch_unwind(AssertUnwindSafe(|| {
block_on(TransportProtocol::Tcp.connect(address.clone()))
}));
match outcome {
Ok(Ok(transport)) => Ok(transport),
Ok(Err(e)) => Err(e.into()),
Err(_) => Err(anyhow::anyhow!("invalid or unresolvable address: {address:?}")),
} Prevention
- Always configure simple-network addresses as 'host:numeric-port' (e.g. 'localhost:9521').
- Use IP literals in environments without DNS (containers, test clusters).
- Pre-flight addresses with `getent hosts <host>` in deployment scripts.
When it happens
Trigger: Passing an address without a port ('localhost'), a non-numeric port ('localhost:http'), or an unresolvable hostname to a simple (TCP/UDP) network client - e.g. a --listen-on/peer address from the proxy or shard configuration, or an address typed into net-proxy invocations.
Common situations: Configuring the simple network layer with bare hostnames when DNS is unavailable in the container; typos in host:port strings; expecting service-name resolution ('validator:9521') in an environment without a working DNS; splitting a config value that leaves an empty string.
Related errors
- owner should be different from spender
- invalid block export configuration: {message}
- Returned AccountInfo should have code: Some(...) and so code
- Returned AccountInfo should have code: Some(...) and so code
- Failed to obtain a port
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/25090f065abe3aa8.
Report an issue: GitHub.