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
- Use IP addresses instead of bare hostnames, e.g. "8.8.8.8,1.1.1.1" (port 53 is implied).
- Prefix hostnames with a scheme and port if needed, e.g. "tcp://dns.google:53" or "udp://dns.google:53".
- Use a predefined key: "google", "cloudflare", or unix:///path/to/dns for a Unix socket.
- 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
- Use IP addresses (port 53 implied) for the simplest valid dns value
- Always give hostnames a scheme and port: udp://host:53
- Avoid bare hostnames and trailing commas in the comma-separated list
- Prefer predefined keys (google, cloudflare) for common providers
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
- dns
- missing `local_dns_addr` or `remote_dns_addr` in configurati
- `protocol` invalid
- invalid `mode`
- `local_dns_address` invalid
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/ad17eacab87122e8.
Report an issue: GitHub.