shadowsocks/shadowsocks-rust · error

balancer.max_server_rtt must be > 0

Error message

balancer.max_server_rtt must be > 0

What it means

During shadowsocks-service configuration validation (Config::check), if balancer.max_server_rtt is set it must represent a duration strictly greater than zero seconds. A zero (or sub-second zero) value would make the balancer's RTT-based server selection logic meaningless, so the config is rejected with ErrorKind::Invalid.

Source

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

        if self.config_type.is_local() {
            if self.local.is_empty() {
                let err = Error::new(
                    ErrorKind::MissingField,
                    "missing `locals` for client configuration",
                    None,
                );
                return Err(err);
            }

            for local_config in &self.local {
                local_config.config.check_integrity()?;
            }

            // Balancer related checks
            if let Some(rtt) = self.balancer.max_server_rtt
                && rtt.as_secs() == 0
            {
                let err = Error::new(ErrorKind::Invalid, "balancer.max_server_rtt must be > 0", None);
                return Err(err);
            }

            if let Some(intv) = self.balancer.check_interval
                && intv.as_secs() == 0
            {
                let err = Error::new(ErrorKind::Invalid, "balancer.check_interval must be > 0", None);
                return Err(err);
            }
        }

        if self.config_type.is_server() && self.server.is_empty() {
            let err = Error::new(
                ErrorKind::MissingField,
                "missing any valid servers in configuration",
                None,
            );
            return Err(err);

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Set max_server_rtt to a positive duration in your config, e.g. max_server_rtt = "500ms" or a value > 0 seconds.
  2. If you do not want an RTT cap, remove the max_server_rtt key entirely so the check is skipped (it is only validated when Some).
  3. If the value comes from a generated config/URL source, fix the generator to omit or correctly compute the RTT value.

Example fix

// before (config.toml)
[balancer]
max_server_rtt = 0

// after
[balancer]
max_server_rtt = "500ms"
Defensive patterns

Strategy: validation

Validate before calling

// Rust: before loading config
if let Some(rtt) = balancer_max_server_rtt {
    assert!(rtt.as_secs() > 0 || rtt.subsec_nanos() > 0, "max_server_rtt must be > 0");
}

Prevention

When it happens

Trigger: Loading or building a Config with config_type local (balancer enabled) where the [balancer] max_server_rtt field is present in the config file/URL but parsed as 0 seconds, e.g. max_server_rtt = 0 or an invalid duration that normalizes to zero, followed by Config::check()/from loading.

Common situations: Hand-edited TOML/JSON config files where the author set max_server_rtt = 0 intending 'unlimited' or 'disabled'; copy-pasted config snippets with placeholder 0 values; URL-based config (ss:// or SIP002/SIP008 plugin params) with rtt=0.

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


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