shadowsocks/shadowsocks-rust · error

missing `local_port`

Error message

missing `local_port`

What it means

In the final Local-type validation (config.rs), if `local_address` is set but `local_port` is missing or 0, the library returns ErrorKind::MissingField "missing `local_port`". A local server listens on address:port, so a port must accompany the address. The check also asserts port != 0 afterwards.

Source

Thrown at crates/shadowsocks-service/src/config.rs:1802

        if let Some(m) = config.mode {
            match m.parse::<Mode>() {
                Ok(xm) => global_mode = xm,
                Err(..) => {
                    let e = Error::new(
                        ErrorKind::Malformed,
                        "malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
                        None,
                    );
                    return Err(e);
                }
            }
        }

        match config_type {
            ConfigType::Local => {
                // Standard config
                if config.local_address.is_some() && config.local_port.unwrap_or(0) == 0 {
                    let err = Error::new(ErrorKind::MissingField, "missing `local_port`", None);
                    return Err(err);
                }

                if let Some(local_port) = config.local_port {
                    // local_port won't be 0, it was checked above
                    assert_ne!(local_port, 0);

                    let local_addr =
                        get_local_address(config.local_address, local_port, config.ipv6_first.unwrap_or(false));

                    // shadowsocks uses SOCKS5 by default
                    let mut local_config = LocalConfig::new(ProtocolType::Socks);
                    local_config.addr = Some(local_addr);
                    local_config.mode = global_mode;
                    local_config.protocol = match config.protocol {
                        None => ProtocolType::Socks,
                        Some(p) => match p.parse::<ProtocolType>() {
                            Ok(p) => p,

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Add a non-zero `local_port` to the configuration (e.g. "local_port": 1080).
  2. In code, set config.local_port = Some(port) before validating.
  3. If only the address should be configured, also verify the port key is not being overwritten to 0 by template/ENV logic.

Example fix

// before
{ "local_address": "127.0.0.1" }
// after
{ "local_address": "127.0.0.1", "local_port": 1080 }
Defensive patterns

Strategy: validation

Validate before calling

if raw.get("local_address").is_some() && raw.get("local_port").and_then(|p| p.as_u64()).unwrap_or(0) == 0 {
    return Err("local_address requires a non-zero local_port");
}

Type guard

fn local_port_ok(cfg: &Config) -> bool {
    cfg.local_address.is_none() || matches!(cfg.local_port, Some(p) if p != 0)
}

Try / catch

match Config::load(path) {
    Ok(cfg) => start(cfg),
    Err(e) if e.to_string().contains("missing `local_port`") => eprintln!("set a non-zero local_port when local_address is specified"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling Config::validate() (or Config::load with ConfigType::Local) where config.local_address is Some but config.local_port is None or Some(0).

Common situations: A JSON config specifying "local_address" but omitting "local_port"; setting local_port to 0 expecting an OS-assigned port (not allowed here); programmatically built configs missing the local_port setter.

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/98c748f4e362ed7a. Report an issue: GitHub.