{"record":{"id":"25090f065abe3aa8","repo":"linera-io/linera-protocol","slug":"invalid-address-to-connect-to","errorCode":null,"errorMessage":"Invalid address to connect to","messagePattern":"Invalid address to connect to","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-rpc/src/simple/transport.rs","lineNumber":156,"sourceCode":"pub trait Transport:\n    Stream<Item = Result<RpcMessage, codec::Error>> + Sink<RpcMessage, Error = codec::Error>\n{\n}\n\nimpl<T> Transport for T where\n    T: Stream<Item = Result<RpcMessage, codec::Error>> + Sink<RpcMessage, Error = codec::Error>\n{\n}\n\nimpl TransportProtocol {\n    /// Creates a transport for this protocol.\n    pub async fn connect(\n        self,\n        address: impl ToSocketAddrs,\n    ) -> Result<impl Transport, std::io::Error> {\n        let mut addresses = lookup_host(address)\n            .await\n            .expect(\"Invalid address to connect to\");\n        let address = addresses\n            .next()\n            .expect(\"Couldn't resolve address to connect to\");\n\n        let stream: futures::future::Either<_, _> = match self {\n            TransportProtocol::Udp => {\n                let socket = UdpSocket::bind(&\"0.0.0.0:0\").await?;\n\n                UdpFramed::new(socket, Codec)\n                    .with(move |message| future::ready(Ok((message, address))))\n                    .map_ok(|(message, _address)| message)\n                    .left_stream()\n            }\n            TransportProtocol::Tcp => {\n                let stream = TcpStream::connect(address).await?;\n\n                Framed::new(stream, Codec).right_stream()\n            }","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-rpc/src/simple/transport.rs#L138-L174","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet transport = TransportProtocol::Tcp.connect(\"validator\").await?; // no port -> panic\n\n// after\nlet transport = TransportProtocol::Tcp.connect(\"validator:9521\").await?;\n\n// when embedding, validate first\nif tokio::net::lookup_host((host.as_str(), port)).await.is_err() {\n    return Err(anyhow::anyhow!(\"cannot resolve {host}:{port}\"));\n}","handlingStrategy":"validation","validationCode":"// Validate host:port resolution before calling connect:\nasync fn resolvable(addr: &str) -> bool {\n    tokio::net::lookup_host(addr.to_string()).await.map(|mut s| s.next().is_some()).unwrap_or(false)\n}\nif !resolvable(&peer_address).await {\n    anyhow::bail!(\"address '{peer_address}' is malformed or unresolvable; use host:port with a numeric port\");\n}","typeGuard":"fn is_host_port(s: &str) -> bool {\n    s.parse::<std::net::SocketAddr>().is_ok()\n        || s.rsplit_once(':').map(|(h, p)| !h.is_empty() && p.parse::<u16>().is_ok()).unwrap_or(false)\n}","tryCatchPattern":"// The library panics during resolution despite returning io::Result; wrap with catch_unwind when embedding:\nlet outcome = std::panic::catch_unwind(AssertUnwindSafe(|| {\n    block_on(TransportProtocol::Tcp.connect(address.clone()))\n}));\nmatch outcome {\n    Ok(Ok(transport)) => Ok(transport),\n    Ok(Err(e)) => Err(e.into()),\n    Err(_) => Err(anyhow::anyhow!(\"invalid or unresolvable address: {address:?}\")),\n}","preventionTips":["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."],"tags":["linera-rpc","network","dns","address-resolution","panic","rust"],"backgroundTag":"dns-resolution-failure","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}