shadowsocks/shadowsocks-rust · error

invalid `dns` value, can only be…

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.

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.

Appendix: 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)