shadowsocks/shadowsocks-rust · error

`local-addr` is required for protocol {}

Error message

`local-addr` is required for protocol {}

What it means

When a `--protocol` (or `--local-addr`) is given but `--local-addr` (LOCAL_ADDR) is absent, create() requires it for every protocol except `tun`, which binds no local listening socket and is exempt. If the exemption doesn't apply, it panics. This enforces that the local server knows where to listen for client traffic.

Source

Thrown at src/service/local.rs:738

                #[cfg(feature = "local-redir")]
                Some("redir") => ProtocolType::Redir,
                #[cfg(feature = "local-dns")]
                Some("dns") => ProtocolType::Dns,
                #[cfg(feature = "local-tun")]
                Some("tun") => ProtocolType::Tun,
                Some(p) => panic!("not supported `protocol` \"{p}\""),
                None => ProtocolType::Socks,
            };

            let mut local_config = LocalConfig::new(protocol);
            match matches.get_one::<ServerAddr>("LOCAL_ADDR").cloned() {
                Some(local_addr) => local_config.addr = Some(local_addr),
                None => {
                    #[cfg(feature = "local-tun")]
                    if protocol == ProtocolType::Tun {
                        // `tun` protocol doesn't need --local-addr
                    } else {
                        panic!("`local-addr` is required for protocol {}", protocol.as_str());
                    }
                }
            }

            if let Some(udp_bind_addr) = matches.get_one::<ServerAddr>("UDP_BIND_ADDR").cloned() {
                local_config.udp_addr = Some(udp_bind_addr);
            }

            if let Some(udp_associate_addr) = matches.get_one::<ServerAddr>("UDP_ASSOCIATE_ADDR").cloned() {
                local_config.udp_associate_addr = Some(udp_associate_addr);
            }

            #[cfg(feature = "local-tunnel")]
            if let Some(addr) = matches.get_one::<Address>("FORWARD_ADDR").cloned() {
                local_config.forward_addr = Some(addr);
            }

            #[cfg(feature = "local-redir")]

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Add `--local-addr <ip:port>` (or `-b`), e.g. `sslocal -b 127.0.0.1:1080 -s server:8388 -p pass`
  2. If you truly want TUN mode, pass `--protocol tun` (no local-addr needed) and build with the local-tun feature
  3. Switch to a JSON config file where `local_addr` is set, and launch sslocal with `-c config.json`

Example fix

// before
sslocal --protocol dns -s example.com:8388 -p pass
// after
sslocal --protocol dns -b 127.0.0.1:1053 -s example.com:8388 -p pass
Defensive patterns

Strategy: validation

Validate before calling

let protocol = std::env::var("PROTOCOL").unwrap_or_else(|_| "socks".into());
if protocol != "tun" && !args.iter().any(|a| a == "-b" || a.starts_with("--local-addr")) {
    panic!("--local-addr is required for protocol {protocol}");
}

Try / catch

// panic is not catchable in stable Rust; check exit status when spawning:
let status = Command::new("sslocal").args(&args).status()?;
if !status.success() { /* grep stderr for '`local-addr` is required' */ }

Prevention

When it happens

Trigger: Running `sslocal --protocol http|socks|tunnel|redir|dns` without `--local-addr` / `-b <addr>` on a build with local-tun enabled (the cfg'd if/else panics in the else branch); equivalently on non-tun builds any protocol without `-b`.

Common situations: Users configuring a TUN-less DNS/HTTP proxy from a TUN tutorial that omitted `-b`; scripts migrated from config-file usage where `local_addr` was set in JSON but CLI flags were added piecemeal.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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