shadowsocks/shadowsocks-rust · error

invalid `dns` value, can only be [(tcp|udp)://]host[:port][,

Error message

invalid `dns` value, can only be [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like "google", "cloudflare"

What it means

The dns config value is parsed into a list of nameserver socket addresses. Each comma-separated part must be a SocketAddr, an IpAddr (port defaults to 53), or a predefined key like "google"/"cloudflare"; otherwise this Error with ErrorKind::Invalid is thrown. It means the dns string does not match any accepted nameserver format.

Source

Thrown at crates/shadowsocks-service/src/config.rs:2769

        // If enables Trust-DNS, then it supports multiple nameservers
        //
        // Set ips directly
        // Similar to shadowsocks-libev's `ares_set_servers_ports_csv`
        //
        // ```
        // host[:port][,host[:port]]...
        // ```
        //
        // For example:
        //     `192.168.1.100,192.168.1.101,3.4.5.6`
        let mut nameservers_config = Vec::new();
        for part in nameservers.split(',') {
            let socket_addr = if let Ok(socket_addr) = part.parse::<SocketAddr>() {
                socket_addr
            } else if let Ok(ipaddr) = part.parse::<IpAddr>() {
                SocketAddr::new(ipaddr, 53)
            } else {
                let e = Error::new(
                    ErrorKind::Invalid,
                    "invalid `dns` value, can only be [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like \"google\", \"cloudflare\"",
                    None,
                );
                return Err(e);
            };

            if protocol.enable_tcp() && protocol.enable_udp() {
                let mut tcp_config = ConnectionConfig::tcp();
                tcp_config.port = socket_addr.port();
                let mut udp_config = ConnectionConfig::udp();
                udp_config.port = socket_addr.port();
                let ns_config = NameServerConfig::new(socket_addr.ip(), true, vec![tcp_config, udp_config]);
                nameservers_config.push(ns_config);
            } else if protocol.enable_udp() {
                let mut udp_config = ConnectionConfig::udp();
                udp_config.port = socket_addr.port();
                let ns_config = NameServerConfig::new(socket_addr.ip(), true, vec![udp_config]);

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Use IP addresses instead of bare hostnames, e.g. "8.8.8.8,1.1.1.1" (port 53 is implied).
  2. Prefix hostnames with a scheme and port if needed, e.g. "tcp://dns.google:53" or "udp://dns.google:53".
  3. Use a predefined key: "google", "cloudflare", or unix:///path/to/dns for a Unix socket.
  4. Remove stray whitespace and trailing commas from the comma-separated list.

Example fix

// before
"dns": "dns.google"
// after
"dns": "udp://dns.google:53"
Defensive patterns

Strategy: validation

Validate before calling

fn validate_dns_value(dns: &str) -> Result<(), String> {
    for part in dns.split(',') {
        let p = part.trim();
        if p.is_empty() { return Err("empty nameserver segment (stray comma?)".into()); }
        let ok = p.parse::<std::net::SocketAddr>().is_ok()
            || p.parse::<std::net::IpAddr>().is_ok()
            || p.starts_with("tcp://") || p.starts_with("udp://") || p.starts_with("unix://")
            || matches!(p, "google" | "cloudflare");
        if !ok { return Err(format!("invalid nameserver: {p}")); }
    }
    Ok(())
}

Type guard

fn is_accepted_dns_entry(part: &str) -> bool {
    part.parse::<std::net::SocketAddr>().is_ok()
        || part.parse::<std::net::IpAddr>().is_ok()
        || part.starts_with("tcp://") || part.starts_with("udp://") || part.starts_with("unix://")
        || matches!(part, "google" | "cloudflare")
}

Try / catch

match validate_dns_value(&dns_value) {
    Ok(()) => { /* proceed to config build */ }
    Err(msg) => log::error!("dns config rejected before build: {msg}"),
}

Prevention

When it happens

Trigger: Config field dns (or the nameservers string it expands to) contains a part that is neither [(tcp|udp)://]host[:port], an IP address, unix:///path, nor a predefined provider key. Thrown while parsing nameservers at crates/shadowsocks-service/src/config.rs:2769.

Common situations: Writing dns: "8.8.8.8:53,1.1.1.1" is fine, but hostname forms like "dns.google" without a scheme, empty segments from trailing commas (e.g. "8.8.8.8,"), or typos like " googel " produce this error.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/ad17eacab87122e8. Report an issue: GitHub.