{"record":{"id":"0a03dbedc5a18e5d","repo":"shadowsocks/shadowsocks-rust","slug":"malformed-mode-must-be-one-of-tcp-only-udp","errorCode":null,"errorMessage":"malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`","messagePattern":"malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/config.rs","lineNumber":1788,"sourceCode":"                    // by checking all its remote servers if all of them supports IPv6.\n                    let ip = if ipv6_first {\n                        Ipv6Addr::LOCALHOST.into()\n                    } else {\n                        Ipv4Addr::LOCALHOST.into()\n                    };\n\n                    ServerAddr::from(SocketAddr::new(ip, local_port))\n                }\n            }\n        }\n\n        // Mode\n        let mut global_mode = Mode::TcpOnly;\n        if let Some(m) = config.mode {\n            match m.parse::<Mode>() {\n                Ok(xm) => global_mode = xm,\n                Err(..) => {\n                    let e = Error::new(\n                        ErrorKind::Malformed,\n                        \"malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`\",\n                        None,\n                    );\n                    return Err(e);\n                }\n            }\n        }\n\n        match config_type {\n            ConfigType::Local => {\n                // Standard config\n                if config.local_address.is_some() && config.local_port.unwrap_or(0) == 0 {\n                    let err = Error::new(ErrorKind::MissingField, \"missing `local_port`\", None);\n                    return Err(err);\n                }\n\n                if let Some(local_port) = config.local_port {","sourceCodeStart":1770,"sourceCodeEnd":1806,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/config.rs#L1770-L1806","documentation":"While parsing the server configuration (config.rs, mode section), the `mode` string is parsed into Mode. If it is not exactly one of `tcp_only`, `udp_only`, or `tcp_and_udp`, the parse fails and the library returns ErrorKind::Malformed. This keeps invalid global modes from silently defaulting to TCP-only.","triggerScenarios":"Loading a config whose JSON `mode` field contains a string that Mode::from_str rejects, e.g. \"tcp\", \"TCP_ONLY\", \"tcp-and-udp\", or any typo; typically hit via Config::load / Config::from_str on a JSON config.","commonSituations":"Hand-written configs using wrong casing or abbreviations; older configs using legacy mode spellings; generated configs from third-party tools emitting non-canonical mode values.","solutions":["Change `mode` in the config to exactly one of \"tcp_only\", \"udp_only\", or \"tcp_and_udp\" (all lowercase, with underscores).","Remove the `mode` key entirely to accept the default (Mode::TcpOnly).","Check for typos/casing when the value comes from an environment variable or template substitution."],"exampleFix":"// before\n{ \"mode\": \"TCP-ONLY\" }\n// after\n{ \"mode\": \"tcp_only\" }","handlingStrategy":"validation","validationCode":"const MODES: [&str; 3] = [\"tcp_only\", \"udp_only\", \"tcp_and_udp\"];\nif let Some(m) = raw.get(\"mode\") {\n    if !MODES.contains(&m.as_str().unwrap_or(\"\")) {\n        return Err(format!(\"invalid mode: {m}; must be one of tcp_only, udp_only, tcp_and_udp\"));\n    }\n}","typeGuard":"fn is_valid_mode(s: &str) -> bool {\n    matches!(s, \"tcp_only\" | \"udp_only\" | \"tcp_and_udp\")\n}","tryCatchPattern":"match Config::load(path) {\n    Ok(cfg) => start(cfg),\n    Err(e) if e.to_string().contains(\"malformed `mode`\") => eprintln!(\"mode must be tcp_only, udp_only, or tcp_and_udp (lowercase)\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Parse modes with Mode::from_str in a pre-check before writing configs.","Avoid free-form mode strings from env vars; validate on input.","Quote exact accepted values in config documentation."],"tags":["config","mode","parse"],"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"}