shadowsocks/shadowsocks-rust · error
invalid `mode`
Error message
invalid `mode`
What it means
Raised when a local config entry's `mode` string cannot be parsed into the `Mode` type. Mode controls which relays are enabled (e.g. "tcp_only", "udp_only", "tcp_and_udp"); an unrecognized value is rejected as Malformed instead of silently defaulting.
Source
Thrown at crates/shadowsocks-service/src/config.rs:1913
local.local_udp_address,
local_udp_port,
config.ipv6_first.unwrap_or(false),
);
local_config.udp_addr = Some(local_udp_addr);
}
#[cfg(target_os = "macos")]
{
local_config.launchd_tcp_socket_name = local.launchd_tcp_socket_name;
local_config.launchd_udp_socket_name = local.launchd_udp_socket_name;
}
match local.mode {
Some(mode) => match mode.parse::<Mode>() {
Ok(mode) => local_config.mode = mode,
Err(..) => {
let err = Error::new(ErrorKind::Malformed, "invalid `mode`", None);
return Err(err);
}
},
None => {
// DNS server runs in `TcpAndUdp` mode by default to maintain backwards compatibility
// see https://github.com/shadowsocks/shadowsocks-rust/issues/1281
let mode = match protocol {
#[cfg(feature = "local-dns")]
ProtocolType::Dns => Mode::TcpAndUdp,
_ => global_mode,
};
local_config.mode = mode;
}
}
#[cfg(feature = "local-tunnel")]
if let Some(forward_address) = local.forward_address {View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Use an exact accepted Mode value: "tcp_only", "udp_only", or "tcp_and_udp" (verify against the Mode enum in your version).
- Remove the `mode` field to inherit the default (TCP-only normally; TCP-and-UDP for local-dns).
- Normalize case — values are matched exactly, e.g. "TCP_ONLY" may not parse.
Example fix
// before
{ "mode": "tcp-only" }
// after
{ "mode": "tcp_only" } Defensive patterns
Strategy: validation
Validate before calling
const MODES: [&str; 3] = ["tcp_only", "udp_only", "tcp_and_udp"];
fn validate_mode(entry: &serde_json::Value) -> Result<(), String> {
if let Some(m) = entry.get("mode") {
let s = m.as_str().ok_or("mode must be a string")?;
if !MODES.contains(&s) {
return Err(format!("invalid mode: {s}"));
}
}
Ok(())
} Type guard
fn is_valid_mode(s: &str) -> bool {
matches!(s, "tcp_only" | "udp_only" | "tcp_and_udp")
} Try / catch
match LocalConfig::load_from(config_path) {
Ok(cfg) => start(cfg),
Err(e) if e.to_string().contains("invalid `mode`") => {
eprintln!("Use tcp_only|udp_only|tcp_and_udp: {e}");
std::process::exit(1);
}
Err(e) => return Err(e.into()),
} Prevention
- Use underscores, not hyphens: tcp_only, not tcp-only.
- Keep mode values lowercase and exact per the Mode enum.
- Drop the `mode` key to rely on documented defaults instead of guessing values.
When it happens
Trigger: A `local` entry contains `mode` set to a string not accepted by Mode::from_str, e.g. `"both"`, `"TCP"`, `"tcp-only"` (hyphen instead of underscore), or a typo.
Common situations: Configs copied from other tools with different mode vocabularies; case-sensitivity mistakes; older configs using removed mode names after an upgrade.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- `protocol` invalid
- `server`, `server_port`, `method`, `password` must be provid
- missing `locals` for client configuration
- balancer.max_server_rtt must be > 0
- server method doesn't support Extended Identity Header (EIH)
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/bc6a50e390f18e4f.
Report an issue: GitHub.