shadowsocks/shadowsocks-rust · error
server-addr
Error message
server-addr
What it means
The per-server SERVER_ADDR value is parsed into a ServerAddr via FromStr; an unparseable address makes .expect("server-addr") panic. ServerAddr accepts host:port or domain:port (optionally with a URI-ish form), so the string must resolve to a valid target server.
Source
Thrown at src/service/local.rs:652
.expect("`method` is required");
let password = match matches.get_one::<String>("PASSWORD") {
Some(pwd) => read_variable_field_value(pwd).into(),
None => {
// NOTE: svr_addr should have been checked by crate::vparser
if method.is_none() {
// If method doesn't need a key (none, plain), then we can leave it empty
String::new()
} else {
match crate::password::read_server_password(svr_addr) {
Ok(pwd) => pwd,
Err(..) => panic!("`password` is required for server {svr_addr}"),
}
}
}
};
let svr_addr = svr_addr.parse::<ServerAddr>().expect("server-addr");
let timeout = matches.get_one::<u64>("TIMEOUT").map(|x| Duration::from_secs(*x));
let mut sc = match ServerConfig::new(svr_addr, password, method) {
Ok(sc) => sc,
Err(err) => {
panic!("failed to create ServerConfig, error: {}", err);
}
};
sc.set_source(ServerSource::CommandLine);
if let Some(timeout) = timeout {
sc.set_timeout(timeout);
}
if let Some(p) = matches.get_one::<String>("PLUGIN").cloned() {
let plugin = PluginConfig {
plugin: p,
plugin_opts: matches.get_one::<String>("PLUGIN_OPT").cloned(),
plugin_args: Vec::new(),View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Format the address as host:port, e.g. example.com:8388 or 1.2.3.4:8388.
- Wrap IPv6 literals in brackets: [2001:db8::1]:8388.
- Validate/trim the value in your launcher script before passing it.
Example fix
// before sslocal -b 127.0.0.1:1080 -s "example.com" ... // after sslocal -b 127.0.0.1:1080 -s "example.com:8388" ...
Defensive patterns
Strategy: validation
Validate before calling
fn validate_server_addr(s: &str) -> Result<(), String> {
s.parse::<shadowsocks::config::ServerAddr>()
.map(|_| ())
.map_err(|_| format!("invalid server-addr '{}': expected host:port", s))
} Try / catch
let addr = s.parse::<ServerAddr>().unwrap_or_else(|_| {
eprintln!("invalid server-addr: {}", s);
std::process::exit(2);
}); Prevention
- Always include the port; bracket IPv6 literals like [::1]:8388.
- Trim whitespace and stray quotes from values in scripts.
- Use sip002 URLs only with the URL input path, not the -s flag.
When it happens
Trigger: Passing a malformed SERVER_ADDR to sslocal, e.g. missing port (`example.com`), non-numeric port (`example.com:https`), empty string, or bracket mishandling for IPv6 (`::1:8388` instead of `[::1]:8388`).
Common situations: Hand-edited scripts; IPv6 addresses without brackets; whitespace or quotes captured into the argument; SIP002 URLs pasted into the wrong flag.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- method
- `method` is required
- method
- `method` is required
- plugin-mode must be one of `tcp_only` (default), `udp_only`
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/22ded333c9078987.
Report an issue: GitHub.