shadowsocks/shadowsocks-rust · error
`plugin` shouldn't be an empty string
Error message
`plugin` shouldn't be an empty string
What it means
Each server instance's SIP003/SIP003u plugin, when present, must be a non-empty (non-whitespace) string. Config::check walks all server configs and rejects any whose plugin field is Some but trims to empty with ErrorKind::Malformed.
Source
Thrown at crates/shadowsocks-service/src/config.rs:2916
}
if self.config_type.is_manager() && self.manager.is_none() {
let err = Error::new(
ErrorKind::MissingField,
"missing `manager_addr` and `manager_port` in configuration",
None,
);
return Err(err);
}
for inst in &self.server {
let server = &inst.config;
// Plugin shouldn't be an empty string
if let Some(plugin) = server.plugin()
&& plugin.plugin.trim().is_empty()
{
let err = Error::new(ErrorKind::Malformed, "`plugin` shouldn't be an empty string", None);
return Err(err);
}
// Server's domain name shouldn't be an empty string
match server.addr() {
ServerAddr::SocketAddr(sa) => {
if sa.port() == 0 {
let err = Error::new(ErrorKind::Malformed, "`server_port` shouldn't be 0", None);
return Err(err);
}
if self.config_type.is_local() {
// Only server could bind to INADDR_ANY
let ip = sa.ip();
if ip.is_unspecified() {
let err = Error::new(
ErrorKind::Malformed,
"`server` shouldn't be an unspecified address (INADDR_ANY)",View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Set the plugin field to a real plugin name (e.g. "obfs-local;obfs=http;obfs-host=example.com") or remove the plugin key entirely so it is None.
- In launch scripts, omit the --plugin flag when the PLUGIN variable is empty instead of passing an empty value.
- Fix the ss:// URL or SIP008 source so plugin= is either fully specified or absent.
Example fix
// before
{ "server": "1.2.3.4", "server_port": 8388, "password": "pw", "method": "aes-256-gcm", "plugin": "" }
// after
{ "server": "1.2.3.4", "server_port": 8388, "password": "pw", "method": "aes-256-gcm", "plugin": "obfs-local;obfs=http;obfs-host=example.com" } Defensive patterns
Strategy: validation
Validate before calling
// Before building ss:// URLs or ServerConfig
let plugin: Option<&str> = maybe_plugin.as_deref();
if let Some(p) = plugin {
assert!(!p.trim().is_empty(), "plugin must be a non-empty string");
} Type guard
fn has_plugin(p: &Option<String>) -> bool {
matches!(p, Some(s) if !s.trim().is_empty())
} Prevention
- In scripts, drop the --plugin flag entirely when PLUGIN is empty instead of passing "".
- Never hand-edit the ?plugin= query parameter of ss:// URLs — regenerate the link.
- Sanitize SIP008 subscription data: convert empty plugin strings to absent fields.
When it happens
Trigger: A server config with plugin = "" (or whitespace only) — typically from an ss:// URL with an empty plugin= parameter, SIP008 server entries with empty plugin fields, or a programmatically constructed ServerConfig where plugin was set to Some("").
Common situations: Copy-pasted ss:// links where the plugin parameter was deleted but the ?plugin= key left empty; environment-variable-driven launch scripts that pass PLUGIN=""; SIP008 subscription data with blank plugin strings.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- `protocol` invalid
- `local_port` cannot be 0
- `local_udp_port` cannot be 0
- invalid `mode`
- `tcp_redir` invalid
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/49eb67b063db6c9f.
Report an issue: GitHub.