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

  1. 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.
  2. In launch scripts, omit the --plugin flag when the PLUGIN variable is empty instead of passing an empty value.
  3. 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

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


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