{"record":{"id":"ad17eacab87122e8","repo":"shadowsocks/shadowsocks-rust","slug":"invalid-dns-value-can-only-be-tcp-udp-hos","errorCode":null,"errorMessage":"invalid `dns` value, can only be [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like \"google\", \"cloudflare\"","messagePattern":"invalid `dns` value, can only be \\[\\(tcp\\|udp\\)://\\]host\\[:port\\]\\[,host\\[:port\\]\\]\\.\\.\\., or unix:///path/to/dns, or predefined keys like \"google\", \"cloudflare\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/config.rs","lineNumber":2769,"sourceCode":"        // If enables Trust-DNS, then it supports multiple nameservers\n        //\n        // Set ips directly\n        // Similar to shadowsocks-libev's `ares_set_servers_ports_csv`\n        //\n        // ```\n        // host[:port][,host[:port]]...\n        // ```\n        //\n        // For example:\n        //     `192.168.1.100,192.168.1.101,3.4.5.6`\n        let mut nameservers_config = Vec::new();\n        for part in nameservers.split(',') {\n            let socket_addr = if let Ok(socket_addr) = part.parse::<SocketAddr>() {\n                socket_addr\n            } else if let Ok(ipaddr) = part.parse::<IpAddr>() {\n                SocketAddr::new(ipaddr, 53)\n            } else {\n                let e = Error::new(\n                    ErrorKind::Invalid,\n                    \"invalid `dns` value, can only be [(tcp|udp)://]host[:port][,host[:port]]..., or unix:///path/to/dns, or predefined keys like \\\"google\\\", \\\"cloudflare\\\"\",\n                    None,\n                );\n                return Err(e);\n            };\n\n            if protocol.enable_tcp() && protocol.enable_udp() {\n                let mut tcp_config = ConnectionConfig::tcp();\n                tcp_config.port = socket_addr.port();\n                let mut udp_config = ConnectionConfig::udp();\n                udp_config.port = socket_addr.port();\n                let ns_config = NameServerConfig::new(socket_addr.ip(), true, vec![tcp_config, udp_config]);\n                nameservers_config.push(ns_config);\n            } else if protocol.enable_udp() {\n                let mut udp_config = ConnectionConfig::udp();\n                udp_config.port = socket_addr.port();\n                let ns_config = NameServerConfig::new(socket_addr.ip(), true, vec![udp_config]);","sourceCodeStart":2751,"sourceCodeEnd":2787,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/config.rs#L2751-L2787","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n\"dns\": \"dns.google\"\n// after\n\"dns\": \"udp://dns.google:53\"","handlingStrategy":"validation","validationCode":"fn validate_dns_value(dns: &str) -> Result<(), String> {\n    for part in dns.split(',') {\n        let p = part.trim();\n        if p.is_empty() { return Err(\"empty nameserver segment (stray comma?)\".into()); }\n        let ok = p.parse::<std::net::SocketAddr>().is_ok()\n            || p.parse::<std::net::IpAddr>().is_ok()\n            || p.starts_with(\"tcp://\") || p.starts_with(\"udp://\") || p.starts_with(\"unix://\")\n            || matches!(p, \"google\" | \"cloudflare\");\n        if !ok { return Err(format!(\"invalid nameserver: {p}\")); }\n    }\n    Ok(())\n}","typeGuard":"fn is_accepted_dns_entry(part: &str) -> bool {\n    part.parse::<std::net::SocketAddr>().is_ok()\n        || part.parse::<std::net::IpAddr>().is_ok()\n        || part.starts_with(\"tcp://\") || part.starts_with(\"udp://\") || part.starts_with(\"unix://\")\n        || matches!(part, \"google\" | \"cloudflare\")\n}","tryCatchPattern":"match validate_dns_value(&dns_value) {\n    Ok(()) => { /* proceed to config build */ }\n    Err(msg) => log::error!(\"dns config rejected before build: {msg}\"),\n}","preventionTips":["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"],"tags":["config","dns","parsing","shadowsocks"],"backgroundTag":"invalid-config-value","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}