zeroclaw-labs/zeroclaw · error · anyhow::Error

Unknown worktree subcommand: {subcommand}. Use: list, add, r

Error message

Unknown worktree subcommand: {subcommand}. Use: list, add, remove, prune

What it means

The git worktree tool's subcommand match covers exactly "list", "add", "remove", and "prune"; any other string falls through to the bail 'Unknown worktree subcommand: {subcommand}. Use: list, add, remove, prune'. This is a vocabulary restriction relative to the git CLI, which also supports lock, unlock, move, and repair — those are intentionally not exposed by this tool. The check is case-sensitive and runs after the missing-parameter check, so the value is guaranteed to be a non-empty string here.

Source

Thrown at crates/zeroclaw-tools/src/git_operations.rs:848

                self.run_git_command(&["worktree", "remove", worktree_path], working_dir)
                    .await?;
                Ok(ToolResult {
                    success: true,
                    output: format!("Worktree removed: {worktree_path}").into(),
                    error: None,
                })
            }
            "prune" => {
                self.run_git_command(&["worktree", "prune"], working_dir)
                    .await?;
                Ok(ToolResult {
                    success: true,
                    output: "Worktree prune completed".to_string().into(),
                    error: None,
                })
            }
            _ => anyhow::bail!(
                "Unknown worktree subcommand: {subcommand}. Use: list, add, remove, prune"
            ),
        }
    }
}

#[async_trait]
impl Tool for GitOperationsTool {
    fn name(&self) -> &str {
        "git_operations"
    }

    fn description(&self) -> &str {
        "Perform structured Git operations (status, diff, log, branch, commit, add, checkout, stash, worktree). Provides parsed JSON output and integrates with security policy for autonomy controls."
    }

    fn parameters_schema(&self) -> serde_json::Value {
        json!({

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Use exactly one of: list, add, remove, prune (lowercase).
  2. For lock/unlock/move/repair, fall back to invoking git directly through a shell tool if your policy allows it — this tool will not grow them via argument tricks.
  3. For removing a worktree, the supported spelling is "remove" (not "rm" or "delete").
  4. When enumerating capabilities programmatically, treat the error's listed vocabulary as the schema of record.

Example fix

// before
let args = serde_json::json!({ "subcommand": "lock", "worktree_path": "/tmp/zc-feature" });
// tool bails: Unknown worktree subcommand: lock. Use: list, add, remove, prune

// after: lock/move are not exposed; remove is the supported cleanup path
let args = serde_json::json!({ "subcommand": "remove", "worktree_path": "/tmp/zc-feature" });
Defensive patterns

Strategy: type-guard

Validate before calling

fn build_worktree_args(subcommand: &str, path: Option<&str>) -> Option<serde_json::Value> {
    WORKTREE_SUBCOMMANDS.contains(&subcommand).then(|| {
        let mut args = serde_json::json!({ "subcommand": subcommand });
        if let Some(p) = path { args["worktree_path"] = serde_json::json!(p); }
        args
    })
}

Type guard

const WORKTREE_SUBCOMMANDS: &[&str] = &["list", "add", "remove", "prune"];
fn is_supported_worktree_subcommand(cmd: &str) -> bool {
    WORKTREE_SUBCOMMANDS.contains(&cmd)
}

Try / catch

match tool_result {
    Err(e) if e.to_string().starts_with("Unknown worktree subcommand") => {
        // the subcommand exists in git but not here; route lock/unlock/move to a shell tool or reject
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling with {"subcommand": "lock"}, {"subcommand": "unlock"}, {"subcommand": "move"}, or {"subcommand": "repair"} — valid git worktree subcommands the tool does not implement. Also typos and case variants: "List", "rm", "delete", "prune " with trailing space (trailing spaces make it a different string, though leading/trailing whitespace inside the JSON string is not trimmed).

Common situations: A developer ports a workflow that relied on `git worktree lock` before a backup; an agent infers subcommands from git's man page instead of the tool's schema; scripted cleanup tries "rm" as a shorthand for remove.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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