shadowsocks/shadowsocks-rust · error

missing remote_dns_addr

Error message

missing remote_dns_addr

What it means

In DNS relay mode, remote_dns_addr specifies the upstream DNS server that queries are forwarded to through the shadowsocks tunnel. DnsBuilder construction expects it unconditionally (Option::expect), so a dns-mode config without remote_dns_addr panics with "missing remote_dns_addr". Like local_dns_addr, this is a hard requirement for dns mode.

Source

Thrown at crates/shadowsocks-service/src/local/mod.rs:412

                    server_builder.set_tcp_redir(local_config.tcp_redir);
                    server_builder.set_udp_redir(local_config.udp_redir);
                    if let Some(udp_addr) = local_config.udp_addr {
                        server_builder.set_udp_bind_addr(udp_addr);
                    }

                    let server = server_builder.build().await?;
                    local_server.redir_servers.push(server);
                }
                #[cfg(feature = "local-dns")]
                ProtocolType::Dns => {
                    let client_addr = match local_config.addr {
                        Some(a) => a,
                        None => return Err(io::Error::other("dns requires local address")),
                    };

                    let mut server_builder = {
                        let local_addr = local_config.local_dns_addr.expect("missing local_dns_addr");
                        let remote_addr = local_config.remote_dns_addr.expect("missing remote_dns_addr");
                        let client_cache_size = local_config.client_cache_size.unwrap_or(5);

                        DnsBuilder::with_context(
                            context.clone(),
                            client_addr,
                            local_addr.clone(),
                            remote_addr.clone(),
                            balancer,
                            client_cache_size,
                        )
                    };
                    server_builder.set_mode(local_config.mode);

                    #[cfg(target_os = "macos")]
                    if let Some(n) = local_config.launchd_tcp_socket_name {
                        server_builder.set_launchd_tcp_socket_name(n);
                    }
                    #[cfg(target_os = "macos")]

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Add remote_dns_addr to the dns-mode config, e.g. remote_dns_addr = "8.8.8.8:53"
  2. Confirm exact field spelling (remote_dns_addr) — a typo silently produces None
  3. Ensure both local_dns_addr and remote_dns_addr are present together in dns mode
  4. Consult the shadowsocks-service dns-tunnel example config for the full required field set

Example fix

# before
class = "local"
protocol = "dns"
local_address = "127.0.0.1:1080"
local_dns_addr = "127.0.0.1:8053"
# after
class = "local"
protocol = "dns"
local_address = "127.0.0.1:1080"
local_dns_addr = "127.0.0.1:8053"
remote_dns_addr = "8.8.8.8:53"
Defensive patterns

Strategy: validation

Validate before calling

if local_config.protocol == ProtocolType::Dns {
    assert!(local_config.local_dns_addr.is_some(), "dns requires local_dns_addr");
    assert!(local_config.remote_dns_addr.is_some(), "dns requires remote_dns_addr");
}

Type guard

fn dns_upstream_ok(cfg: &LocalConfig) -> bool {
    cfg.protocol != ProtocolType::Dns || cfg.remote_dns_addr.is_some()
}

Try / catch

// expect() panics — pre-validate
if !dns_upstream_ok(&config) {
    eprintln!("invalid dns config: remote_dns_addr is required (e.g. 8.8.8.8:53)");
    std::process::exit(2);
}
let server = LocalServer::new(context, config)?;

Prevention

When it happens

Trigger: protocol = "dns" config supplies local_dns_addr but not remote_dns_addr (field absent or misspelled, e.g. `remote_dns` instead of `remote_dns_addr`), causing the expect in LocalServer::new to panic.

Common situations: Hand-written dns configs omitting the upstream server; renaming/regression in config keys after upgrading; automated config generators copying dns sections incompletely.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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