{"record":{"id":"3d0aae7066a8c5fe","repo":"zeroclaw-labs/zeroclaw","slug":"edge-tts-binary-path-must-be-a-bare-command-name-w","errorCode":null,"errorMessage":"Edge TTS binary_path must be a bare command name without path separators, got: {raw_path}","messagePattern":"Edge TTS binary_path must be a bare command name without path separators, got: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/tts.rs","lineNumber":646,"sourceCode":"                }\n                std::thread::sleep(std::time::Duration::from_millis(50));\n            }\n        }\n    }\n}\n\nimpl EdgeTtsProvider {\n    /// Allowed basenames for the Edge TTS binary.\n    const ALLOWED_BINARIES: &[&str] = &[\"edge-tts\", \"edge-playback\"];\n\n    pub fn new(alias: &str, config: &TtsProviderConfig) -> Result<Self> {\n        let raw_path = config\n            .binary_path\n            .clone()\n            .filter(|p| !p.trim().is_empty())\n            .unwrap_or_else(|| \"edge-tts\".to_string());\n        if raw_path.contains('/') || raw_path.contains('\\\\') {\n            bail!(\n                \"Edge TTS binary_path must be a bare command name without path separators, got: {raw_path}\"\n            );\n        }\n        if !Self::ALLOWED_BINARIES.contains(&raw_path.as_str()) {\n            bail!(\n                \"Edge TTS binary_path must be one of {:?}, got: {raw_path}\",\n                Self::ALLOWED_BINARIES,\n            );\n        }\n        Ok(Self {\n            alias: alias.to_string(),\n            binary_path: raw_path,\n            #[cfg(test)]\n            binary_args: Vec::new(),\n            timeout: TTS_HTTP_TIMEOUT,\n        })\n    }\n","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/tts.rs#L628-L664","documentation":"EdgeTtsProvider::new rejects a binary_path containing '/' or '\\\\'. Edge TTS runs as a subprocess via tokio::process::Command::new(binary_path), so the config value is executed; the separator check is the first half of an allowlist security boundary that only permits bare command names resolved through PATH.","triggerScenarios":"Setting [providers.tts.edge.<alias>].binary_path to an absolute path (/usr/local/bin/edge-tts), a relative path (./edge-tts, bin/edge-tts), or any Windows path with a backslash. Empty or unset values are fine and default to \"edge-tts\".","commonSituations":"Admins harden the config by pinning an explicit binary location and are surprised the provider refuses it. CI environments installing edge-tts into a venv try to point at the venv's bin directory.","solutions":["Set binary_path to the bare name: binary_path = \"edge-tts\" (or remove the key; it is the default).","Make the intended binary reachable via PATH (add the venv bin directory to PATH, or symlink it into a PATH directory like /usr/local/bin).","Verify resolution with `command -v edge-tts` under the same user that runs the runtime."],"exampleFix":"# before\n[providers.tts.edge.main]\nbinary_path = \"/opt/venvs/tts/bin/edge-tts\"\n\n# after — bare name; ensure /opt/venvs/tts/bin is on PATH (or symlink into /usr/local/bin)\n[providers.tts.edge.main]\nbinary_path = \"edge-tts\"","handlingStrategy":"validation","validationCode":"// Validate the config value before constructing the provider.\nfn is_bare_command_name(p: &str) -> bool {\n    !p.is_empty() && !p.contains('/') && !p.contains('\\\\')\n}\n\nif let Some(bin) = &edge_cfg.binary_path {\n    assert!(is_bare_command_name(bin), \"binary_path must be a bare name; put the directory on PATH\");\n}","typeGuard":"fn is_bare_command(p: &str) -> bool {\n    !p.contains('/') && !p.contains('\\\\')\n}","tryCatchPattern":null,"preventionTips":["Treat binary_path as a name, not a path: default \"edge-tts\" needs no override in most setups.","Make binary locations reachable via PATH (symlink into /usr/local/bin) instead of writing paths into config.","Lint config files for '/' or '\\\\' in binary_path during CI."],"tags":["edge-tts","tts","config","validation","security"],"backgroundTag":"config-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}