{"record":{"id":"485b990a9b1f0c9e","repo":"rathole-org/rathole","slug":"missing-semicolon","errorCode":null,"errorMessage":"missing semicolon","messagePattern":"missing semicolon","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/helper.rs","lineNumber":62,"sourceCode":"}\n\n#[allow(dead_code)]\npub fn feature_neither_compile(feature1: &str, feature2: &str) -> ! {\n    panic!(\n        \"Neither of the feature '{}' or '{}' is compiled in this binary. Please re-compile rathole\",\n        feature1, feature2\n    )\n}\n\npub async fn to_socket_addr<A: ToSocketAddrs>(addr: A) -> Result<SocketAddr> {\n    lookup_host(addr)\n        .await?\n        .next()\n        .ok_or_else(|| anyhow!(\"Failed to lookup the host\"))\n}\n\npub fn host_port_pair(s: &str) -> Result<(&str, u16)> {\n    let semi = s.rfind(':').expect(\"missing semicolon\");\n    Ok((&s[..semi], s[semi + 1..].parse()?))\n}\n\n/// Create a UDP socket and connect to `addr`\npub async fn udp_connect<A: ToSocketAddrs>(addr: A, prefer_ipv6: bool) -> Result<UdpSocket> {\n\n    let (socket_addr, bind_addr);\n\n    match prefer_ipv6 {\n        false => {\n            socket_addr = to_socket_addr(addr).await?;\n\n            bind_addr = match socket_addr {\n                SocketAddr::V4(_) => \"0.0.0.0:0\",\n                SocketAddr::V6(_) => \":::0\",\n            };\n        },\n        true => {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/rathole-org/rathole/blob/a292f7ed5402f840415fc6a53827da2f34337856/src/helper.rs#L44-L80","documentation":"host_port_pair splits an `host:port` string at the last colon via rfind(':') and panics with \"missing semicolon\" if there is no colon. The panic means the address string passed to tcp_connect_with_proxy/connect lacked a port component.","triggerScenarios":"Calling host_port_pair (via connect or tcp_connect_with_proxy) with an address string like \"example.com\" or \"example.com.\" without `:port`.","commonSituations":"Users writing just a hostname in the config's remote_addr; shell/env interpolation dropping the `:port` suffix; copy-paste of a URL where the port got separated; IPv6 literals without brackets plus port, causing a malformed string.","solutions":["Append the port to the address, e.g. `example.com:443`.","Validate user-supplied addresses contain a `host:port` before passing them in.","For IPv6 literals use bracketed form `[::1]:443` so the last-colon split is unambiguous.","Consider using a parsing helper (SocketAddr::from_str) to get a proper error instead of a panic."],"exampleFix":"// before\nlet addr = \"example.com\"; // panics in host_port_pair\n// after\nlet addr = \"example.com:443\";","handlingStrategy":"validation","validationCode":"fn ensure_host_port(s: &str) -> Result<(), String> {\n    match s.rfind(':') {\n        Some(i) if i + 1 < s.len() && s[i+1..].chars().all(|c| c.is_ascii_digit()) => Ok(()),\n        _ => Err(format!(\"address '{}' must be in host:port form\", s)),\n    }\n}","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(|| host_port_pair(addr))\n    .and_then(|r| r)\n    .map_err(|_| anyhow!(\"address '{}' must include a port (host:port)\", addr));","preventionTips":["Always include the port in address configs","Use bracketed [host]:port form for IPv6 literals","Validate addresses at config-load time"],"tags":["panic","address-format","host-port","parsing"],"backgroundTag":"invalid-argument-format","analyzedSha":"a292f7ed5402f840415fc6a53827da2f34337856","analyzedAt":"2026-09-07T09:56:55.739Z","contentChangedAt":"2026-09-07T09:56:55.739Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}