zeroclaw-labs/zeroclaw · error

Edge TTS binary_path must be a bare command name without pat

Error message

Edge TTS binary_path must be a bare command name without path separators, got: {raw_path}

What it means

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.

Source

Thrown at crates/zeroclaw-channels/src/tts.rs:646

                }
                std::thread::sleep(std::time::Duration::from_millis(50));
            }
        }
    }
}

impl EdgeTtsProvider {
    /// Allowed basenames for the Edge TTS binary.
    const ALLOWED_BINARIES: &[&str] = &["edge-tts", "edge-playback"];

    pub fn new(alias: &str, config: &TtsProviderConfig) -> Result<Self> {
        let raw_path = config
            .binary_path
            .clone()
            .filter(|p| !p.trim().is_empty())
            .unwrap_or_else(|| "edge-tts".to_string());
        if raw_path.contains('/') || raw_path.contains('\\') {
            bail!(
                "Edge TTS binary_path must be a bare command name without path separators, got: {raw_path}"
            );
        }
        if !Self::ALLOWED_BINARIES.contains(&raw_path.as_str()) {
            bail!(
                "Edge TTS binary_path must be one of {:?}, got: {raw_path}",
                Self::ALLOWED_BINARIES,
            );
        }
        Ok(Self {
            alias: alias.to_string(),
            binary_path: raw_path,
            #[cfg(test)]
            binary_args: Vec::new(),
            timeout: TTS_HTTP_TIMEOUT,
        })
    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Set binary_path to the bare name: binary_path = "edge-tts" (or remove the key; it is the default).
  2. 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).
  3. Verify resolution with `command -v edge-tts` under the same user that runs the runtime.

Example fix

# before
[providers.tts.edge.main]
binary_path = "/opt/venvs/tts/bin/edge-tts"

# after — bare name; ensure /opt/venvs/tts/bin is on PATH (or symlink into /usr/local/bin)
[providers.tts.edge.main]
binary_path = "edge-tts"
Defensive patterns

Strategy: validation

Validate before calling

// Validate the config value before constructing the provider.
fn is_bare_command_name(p: &str) -> bool {
    !p.is_empty() && !p.contains('/') && !p.contains('\\')
}

if let Some(bin) = &edge_cfg.binary_path {
    assert!(is_bare_command_name(bin), "binary_path must be a bare name; put the directory on PATH");
}

Type guard

fn is_bare_command(p: &str) -> bool {
    !p.contains('/') && !p.contains('\\')
}

Prevention

When it happens

Trigger: 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".

Common situations: 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.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/3d0aae7066a8c5fe. Report an issue: GitHub.