Hmbown/CodeWhale · error · anyhow::Error

unknown runtime backend `{other}` (use tmux|inline|vm|ci)

Error message

unknown runtime backend `{other}` (use tmux|inline|vm|ci)

What it means

Thrown by RuntimeBackend::parse when the backend string, after trimming and lowercasing, is not one of the four supported backends: tmux, inline, vm, or ci. Parsing is case-insensitive and whitespace-tolerant, so the failure means the value is genuinely a different word (e.g. 'docker', 'ssh', 'local') or a typo.

Source

Thrown at crates/lane/src/runtime.rs:44

}

impl RuntimeBackendKind {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Tmux => "tmux",
            Self::Inline => "inline",
            Self::Vm => "vm",
            Self::Ci => "ci",
        }
    }

    pub fn parse(raw: &str) -> Result<Self> {
        match raw.trim().to_ascii_lowercase().as_str() {
            "tmux" => Ok(Self::Tmux),
            "inline" => Ok(Self::Inline),
            "vm" => Ok(Self::Vm),
            "ci" => Ok(Self::Ci),
            other => bail!("unknown runtime backend `{other}` (use tmux|inline|vm|ci)"),
        }
    }
}

/// Inputs for starting a lane under a runtime backend.
#[derive(Clone)]
pub struct LaneStartSpec {
    /// Command argv to run inside the backend (e.g. `codewhale exec …`).
    pub command: Vec<String>,
    /// Working directory for the command (defaults to worktree or cwd).
    pub cwd: Option<PathBuf>,
    /// Process-local runtime overrides. Values are never written into the
    /// Lane record or command argv; tmux bridges them through a private 0600
    /// environment file that the detached shell removes before execution.
    pub environment: Vec<(String, String)>,
    /// Executable that exposes Codewhale's hidden `lane-log-proxy` command.
    /// Required by tmux so arbitrary/binary child output is framed as valid
    /// NDJSON without trusting a shell pipeline.

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Use one of the four supported values: tmux, inline, vm, or ci (case-insensitive)
  2. Check for typos and stray characters — 'in line' with a space or 'vm:' with a suffix both fail
  3. If you need a container/remote feel today, map it onto 'vm' or 'ci' as documented, or remove the setting to use the default backend

Example fix

# before
runtime = "docker"

# after
runtime = "vm"
Defensive patterns

Strategy: type-guard

Validate before calling

fn valid_backend(raw: &str) -> bool {
    matches!(raw.trim().to_ascii_lowercase().as_str(), "tmux" | "inline" | "vm" | "ci")
}

assert!(valid_backend(&raw), "runtime must be one of tmux|inline|vm|ci");

Type guard

fn is_supported_backend(raw: &str) -> bool {
    matches!(raw.trim().to_ascii_lowercase().as_str(), "tmux" | "inline" | "vm" | "ci")
}

Try / catch

let backend = match RuntimeBackend::parse(&raw) {
    Ok(b) => b,
    Err(err) if err.to_string().contains("unknown runtime backend") => {
        RuntimeBackend::parse("tmux")? // explicit fallback to default backend
    }
    Err(err) => return Err(err),
};

Prevention

When it happens

Trigger: A runtime = "docker" or "remote" entry in lane/runtime config, a CLI flag like --runtime ssh, or a typo such as "in line" or "tmux2". Only the exact four identifiers (in any case) parse.

Common situations: Assuming a Docker/SSH backend exists because other agent tools have one; config copied between tool versions where backend names changed; machine-generated configs enumerating hypothetical backends.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/e10cebf09ded608d. Report an issue: GitHub.