zeroclaw-labs/zeroclaw · error · anyhow::Error
Branch name contains invalid characters
Error message
Branch name contains invalid characters
What it means
After the single-token shape check passes, git checkout rejects branch names containing '@', '^', or '~' with 'Branch name contains invalid characters'. These characters are the carriers of git revision syntax: '@{' addresses refs like stash@{0} and HEAD@{1}, while '~' and '^' express ancestor ranges like HEAD~2 or main^2. Accepting them would let the 'checkout a branch' operation silently perform reflog jumps or detached-revision checkouts, so the tool restricts checkout to plain branch names. This is a policy restriction of the tool, not a git limitation — the CLI itself accepts those revisions.
Source
Thrown at crates/zeroclaw-tools/src/git_operations.rs:600
.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,
}),
Err(e) => Ok(ToolResult {
success: false,
output: ToolOutput::default(),
error: Some(format!("Checkout failed: {e}")),
}),
}View on GitHub (pinned to 88bb9c8533)
Solutions
- Pass a plain branch name that exists locally, e.g. {"branch": "main"} or {"branch": "feature-x"}.
- For detached-HEAD/history navigation, create or check out a branch at the target revision using the CLI or another tool surface — this tool intentionally will not take HEAD~1.
- If your branch genuinely contains '@', rename it (git branch -m) to a dash-separated name before using this checkout tool.
- Use git_branch-style operations to list valid branch names first and pick from those.
Example fix
// before
let args = serde_json::json!({ "branch": "HEAD~1" }); // revision syntax, not a branch name
// tool bails: Branch name contains invalid characters
// after
let args = serde_json::json!({ "branch": "main" }); Defensive patterns
Strategy: type-guard
Validate before calling
fn build_checkout_args(branch: &str) -> Option<serde_json::Value> {
is_plain_branch_name(branch).then(|| serde_json::json!({ "branch": branch }))
} Type guard
fn is_plain_branch_name(branch: &str) -> bool {
!branch.contains('@') && !branch.contains('^') && !branch.contains('~')
} Try / catch
match tool_result {
Err(e) if e.to_string().contains("Branch name contains invalid characters") => {
// revision syntax was passed; resolve it to a concrete branch name first
}
other => other,
} Prevention
- Never feed revision expressions (HEAD~n, ref@{n}, x^y) into a checkout-branch API; resolve them to branch names first.
- Validate branch names against the tool's denylist ('@', '^', '~') in your own schema layer for earlier, clearer errors.
- Rename legacy branches containing '@' at creation time rather than working around checkout later.
When it happens
Trigger: Calling checkout with {"branch": "HEAD~1"}, {"branch": "main^"}, or {"branch": "stash@{0}"}. Also any legitimately created branch whose name contains '@' (git allows branch names with '@' as long as they are not exactly '@').
Common situations: An agent tries to navigate history and reuses revision syntax in the branch field; a caller wants to check out a stashed state via stash@{0}; a branch was created with an email-like name (user@feature) and now cannot be checked out through this tool; porting a shell script that used HEAD~1 directly.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid branch specification
- Blocked potentially dangerous git argument: {arg}
- Path '{}' resolves outside the workspace directory
- Path not allowed: parent-directory traversal is not allowed
- Worktree path '{}' resolves outside the workspace or allowed
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/550c1439d363a2ac.
Report an issue: GitHub.