{"record":{"id":"6027e87ef99d0be2","repo":"shadowsocks/shadowsocks-rust","slug":"protocol-invalid","errorCode":null,"errorMessage":"`protocol` invalid","messagePattern":"`protocol` invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/config.rs","lineNumber":1822,"sourceCode":"                }\n\n                if let Some(local_port) = config.local_port {\n                    // local_port won't be 0, it was checked above\n                    assert_ne!(local_port, 0);\n\n                    let local_addr =\n                        get_local_address(config.local_address, local_port, config.ipv6_first.unwrap_or(false));\n\n                    // shadowsocks uses SOCKS5 by default\n                    let mut local_config = LocalConfig::new(ProtocolType::Socks);\n                    local_config.addr = Some(local_addr);\n                    local_config.mode = global_mode;\n                    local_config.protocol = match config.protocol {\n                        None => ProtocolType::Socks,\n                        Some(p) => match p.parse::<ProtocolType>() {\n                            Ok(p) => p,\n                            Err(..) => {\n                                let err = Error::new(\n                                    ErrorKind::Malformed,\n                                    \"`protocol` invalid\",\n                                    Some(format!(\"unrecognized protocol {p}\")),\n                                );\n                                return Err(err);\n                            }\n                        },\n                    };\n                    #[cfg(target_os = \"macos\")]\n                    {\n                        local_config\n                            .launchd_tcp_socket_name\n                            .clone_from(&config.launchd_tcp_socket_name);\n                        local_config\n                            .launchd_udp_socket_name\n                            .clone_from(&config.launchd_udp_socket_name);\n                    }\n","sourceCodeStart":1804,"sourceCodeEnd":1840,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/config.rs#L1804-L1840","documentation":"This error is raised while parsing a shadowsocks local server configuration when the `protocol` field is present but its string value cannot be parsed into a `ProtocolType` (e.g. it is not one of \"socks\", \"http\", \"tunnel\", etc.). The library fails fast with ErrorKind::Malformed because an unrecognized protocol would otherwise produce a local server that cannot be started. It includes the offending value as detail (`unrecognized protocol {p}`).","triggerScenarios":"Loading a local config (JSON/URL) whose per-server or global entry has `protocol` set to a string that does not match any ProtocolType variant — e.g. `\"protocol\": \"socks5\"` or `\"SOCKS\"` or a typo like `\"sock\"`.","commonSituations":"Hand-edited config.json files with typos or wrong casing; configs copied from other shadowsocks implementations that use different protocol names; schema drift after upgrading where an old/alias protocol name is no longer accepted.","solutions":["Check the config value of `protocol` and use an exact accepted variant, e.g. \"socks\", \"http\", \"tunnel\" (values accepted by ProtocolType::from_str).","Remove the `protocol` field entirely to get the default (ProtocolType::Socks).","Verify no trailing whitespace or BOM in the JSON string value.","Consult the ProtocolType enum docs in the installed shadowsocks-service version, since accepted values can vary by version."],"exampleFix":"// before\n{ \"protocol\": \"socks5\", \"local_port\": 1080 }\n// after\n{ \"protocol\": \"socks\", \"local_port\": 1080 }","handlingStrategy":"validation","validationCode":"const PROTOCOLS: [&str; 4] = [\"socks\", \"http\", \"tunnel\", \"redir\"]; // check your version's ProtocolType\nfn validate_protocol(cfg: &serde_json::Value) -> Result<(), String> {\n    match cfg.get(\"protocol\") {\n        None => Ok(()),\n        Some(p) => {\n            let s = p.as_str().ok_or(\"protocol must be a string\")?;\n            if PROTOCOLS.contains(&s) { Ok(()) } else { Err(format!(\"unrecognized protocol {s}\")) }\n        }\n    }\n}","typeGuard":"fn is_valid_protocol(s: &str) -> bool {\n    matches!(s, \"socks\" | \"http\" | \"tunnel\" | \"redir\")\n}","tryCatchPattern":"match LocalConfig::load_from(config_path) {\n    Ok(cfg) => start(cfg),\n    Err(e) if e.kind() == ErrorKind::Malformed => {\n        eprintln!(\"Bad config: {e}\"); // inspect `protocol` value and fix spelling\n        std::process::exit(1);\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Keep a JSON schema for your config and validate before loading.","Only use protocol spellings copied from the official shadowsocks-rust docs.","Lint configs in CI with a preflight load against the same library version.","Avoid manual edits on production configs; diff and review changes."],"tags":["config","validation","shadowsocks"],"backgroundTag":"invalid-enum-value","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}