shadowsocks/shadowsocks-rust · error
tunnel requires forward address
Error message
tunnel requires forward address
What it means
The local server's Tunnel protocol mode requires a forward_addr in the LocalConfig: the destination to which all tunneled traffic is forwarded. The code expects it unconditionally (Option::expect) when building TunnelBuilder, so a Tunnel-mode config without forward_addr panics with "tunnel requires forward address". Unlike some other errors this is a panic, not an io::Error return.
Source
Thrown at crates/shadowsocks-service/src/local/mod.rs:332
if let Some(n) = local_config.launchd_tcp_socket_name {
server_builder.set_launchd_tcp_socket_name(n);
}
#[cfg(target_os = "macos")]
if let Some(n) = local_config.launchd_udp_socket_name {
server_builder.set_launchd_udp_socket_name(n);
}
let server = server_builder.build().await?;
local_server.socks_servers.push(server);
}
#[cfg(feature = "local-tunnel")]
ProtocolType::Tunnel => {
let client_addr = match local_config.addr {
Some(a) => a,
None => return Err(io::Error::other("tunnel requires local address")),
};
let forward_addr = local_config.forward_addr.expect("tunnel requires forward address");
let mut server_builder =
TunnelBuilder::with_context(context.clone(), forward_addr.clone(), client_addr, balancer);
if let Some(c) = config.udp_max_associations {
server_builder.set_udp_capacity(c);
}
if let Some(d) = config.udp_timeout {
server_builder.set_udp_expiry_duration(d);
}
server_builder.set_mode(local_config.mode);
if let Some(udp_addr) = local_config.udp_addr {
server_builder.set_udp_bind_addr(udp_addr);
}
#[cfg(target_os = "macos")]
if let Some(n) = local_config.launchd_tcp_socket_name {
server_builder.set_launchd_tcp_socket_name(n);View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Add forward_addr to the tunnel local config, e.g. forward_addr = "target.host:port"
- Double-check the config section actually uses protocol = "tunnel" only where forward_addr is defined
- Prefer explicit configuration over defaults — validate config files before deployment
- If tunnel mode is unintended, switch protocol back to socks/http and remove the tunnel assumptions
Example fix
# before class = "local" protocol = "tunnel" local_address = "127.0.0.1:1080" # after class = "local" protocol = "tunnel" local_address = "127.0.0.1:1080" forward_addr = "example.com:80"
Defensive patterns
Strategy: validation
Validate before calling
// Validate tunnel config before constructing LocalServer
if local_config.protocol == ProtocolType::Tunnel {
assert!(local_config.addr.is_some(), "tunnel requires local address");
assert!(local_config.forward_addr.is_some(), "tunnel requires forward_addr");
} Type guard
fn tunnel_config_ok(cfg: &LocalConfig) -> bool {
cfg.protocol != ProtocolType::Tunnel || (cfg.addr.is_some() && cfg.forward_addr.is_some())
} Try / catch
// This is a panic (expect), not an Err — guard by validating config first
if !tunnel_config_ok(&config) {
eprintln!("invalid tunnel config: forward_addr is required");
std::process::exit(2);
}
let server = LocalServer::new(context, config)?; Prevention
- Always pair protocol = "tunnel" with a forward_addr in the config
- Run shadowsocks' config validation (or a schema check) before launch
- Keep tunnel configs in a separate template including all required fields
- Remember this path panics via expect — never construct LocalServer with unvalidated user input
When it happens
Trigger: Configuring protocol = "tunnel" with a local listening address but omitting forward_addr (e.g. missing `forward_addr = "example.com:80"` in the [local] section), then constructing LocalServer::new.
Common situations: Copy-pasting a SOCKS/HTTP local config and switching protocol to tunnel without adding forward_addr; older config files predating the tunnel option; tooling generating configs that skip tunnel-specific fields.
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
- missing local_dns_addr
- missing remote_dns_addr
- all plugins are exited. all connections may fail, check your
- unsupported syslog facility: {}
- `password` is required for server {svr_addr}
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/ea2dcf2a55470e2e.
Report an issue: GitHub.