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

Invalid branch specification

Error message

Invalid branch specification

What it means

The git checkout tool takes a 'branch' string, sanitizes it into whitespace-separated tokens, and requires exactly one non-empty token. Zero tokens (blank branch) or more than one token (any internal whitespace) bails with 'Invalid branch specification'. The single-token rule exists because the sanitized result is used as the sole branch argument to `git checkout`, so a multi-token string would either be ambiguous or interpreted as extra arguments. This is a shape check on the parameter, distinct from the character-level check that follows it.

Source

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

        args: serde_json::Value,
        working_dir: &std::path::Path,
    ) -> anyhow::Result<ToolResult> {
        let branch = args.get("branch").and_then(|v| v.as_str()).ok_or_else(|| {
            ::zeroclaw_log::record!(
                WARN,
                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                    .with_attrs(::serde_json::json!({"param": "branch"})),
                "git_operations: missing branch parameter"
            );
            anyhow::Error::msg("Missing 'branch' parameter")
        })?;

        // Sanitize branch name
        let sanitized = self.sanitize_git_args(branch)?;

        if sanitized.is_empty() || sanitized.len() > 1 {
            anyhow::bail!("Invalid branch specification");
        }

        let branch_name = &sanitized[0];

        // Block dangerous branch names
        if branch_name.contains('@') || branch_name.contains('^') || branch_name.contains('~') {
            anyhow::bail!("Branch name contains invalid characters");
        }

        let output = self
            .run_git_command(&["checkout", branch_name], working_dir)
            .await;

        match output {
            Ok(_) => Ok(ToolResult {
                success: true,
                output: format!("Switched to branch: {branch_name}").into(),
                error: None,

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Pass exactly one whitespace-free branch name, e.g. {"branch": "feature-login"}.
  2. Use hyphens or underscores in branch names instead of spaces when you control branch creation.
  3. Default the branch in the caller (e.g. to the repo's main branch) when the configured value is blank, instead of forwarding an empty string.
  4. Trim the value and verify it has no internal whitespace before invoking the tool.

Example fix

// before
let args = serde_json::json!({ "branch": "feature login refactor" }); // 3 tokens after sanitize
// tool bails: Invalid branch specification

// after
let args = serde_json::json!({ "branch": "feature-login-refactor" });
Defensive patterns

Strategy: validation

Validate before calling

fn build_checkout_args(branch: &str) -> Option<serde_json::Value> {
    let tokens: Vec<&str> = branch.split_whitespace().collect();
    (tokens.len() == 1).then(|| serde_json::json!({ "branch": tokens[0] }))
}

Type guard

fn is_single_token_spec(branch: &str) -> bool {
    let mut tokens = branch.split_whitespace();
    tokens.next().is_some() && tokens.next().is_none()
}

Try / catch

match tool_result {
    Err(e) if e.to_string().contains("Invalid branch specification") => {
        // the value had zero or 2+ whitespace tokens; log it and fall back to a known branch
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling checkout with {"branch": ""} or {"branch": " "} (zero tokens), or with {"branch": "feature login refactor"} / {"branch": "origin main"} (whitespace splits into 2+ tokens). Any branch value containing a space, tab, or newline triggers it.

Common situations: A caller interpolates a human-readable description into the branch field; an agent passes a git ref expression that contains a space; a config value for the default branch is empty; copy-pasting a branch name with a trailing comment or space-padded padding from logs.

Related errors


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