cloudflare/quiche · error

--connect-to is expected to be a string containing an IPv4…

Error message

--connect-to is expected to be a string containing an IPv4 or IPv6 address with a port. E.g. 192.0.2.0:443

What it means

h3i's resolve_socket_addrs parses the --connect-to CLI value with SocketAddr::parse and panics on failure with this message. The value must be a literal 'IP:port' string, not a hostname or a bare URL.

Solutions

  1. Pass a literal IPv4/IPv6 address with port, e.g. --connect-to 192.0.2.0:443.
  2. Omit --connect-to so the address is derived from host_port instead.
  3. Pre-resolve the hostname to an IP with dig/host and use that IP.

Example fix

// before
h3i --host_port example.com:443 --connect-to example.com:443
// after
h3i --host_port example.com:443 --connect-to 93.184.216.34:443
Defensive patterns

Strategy: validation

Validate before calling

use std::net::SocketAddr;
let addr: SocketAddr = connect_to.parse()
    .map_err(|_| "--connect-to must be IP:port, e.g. 192.0.2.0:443")?;

Prevention

When it happens

Trigger: Passing --connect-to with a hostname (example.com:443), a scheme (https://192.0.2.0:443), a missing port, or malformed IP to h3i (or quiche-client-style tools sharing this code).

Common situations: Copying a hostname into --connect-to when doing SNI/host overriding; forgetting the port; IPv6 literals without brackets are handled, but URLs are not.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


AI-assisted analysis of cloudflare/quiche@9f96daa2c2 (2026-09-08). Data as JSON: /api/errors/ffb504359066b66b. Report an issue: GitHub.

Appendix: source

Thrown at h3i/src/client/mod.rs:574

    let connect_url = if !args.omit_sni {
        args.host_port.split(':').next()
    } else {
        None
    };

    let (peer_addr, bind_addr) = resolve_socket_addrs(args);

    ParsedArgs {
        peer_addr,
        bind_addr,
        connect_url,
    }
}

fn resolve_socket_addrs(args: &Config) -> (SocketAddr, SocketAddr) {
    // Resolve server address.
    let peer_addr = if let Some(addr) = &args.connect_to {
        addr.parse().expect("--connect-to is expected to be a string containing an IPv4 or IPv6 address with a port. E.g. 192.0.2.0:443")
    } else {
        let x = format!("https://{}", args.host_port);
        *url::Url::parse(&x)
            .unwrap()
            .socket_addrs(|| None)
            .unwrap()
            .first()
            .unwrap()
    };

    // Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
    // server address. This is needed on macOS and BSD variants that don't
    // support binding to IN6ADDR_ANY for both v4 and v6.
    let bind_addr = match peer_addr {
        std::net::SocketAddr::V4(_) => format!("0.0.0.0:{}", args.source_port),
        std::net::SocketAddr::V6(_) => format!("[::]:{}", args.source_port),
    };

View on GitHub (pinned to 9f96daa2c2)