zeroclaw-labs/zeroclaw · error · anyhow::Error
No paths to stage
Error message
No paths to stage
What it means
The git add tool requires a 'paths' string and runs it through sanitize_git_args, which both rejects injection patterns and splits the whitespace-separated pathspec string into individual arguments. If sanitization yields zero tokens (sanitized.is_empty()), the tool bails with 'No paths to stage' before running `git add`. The guard prevents an argument-less `git add` invocation, which would either error or, depending on flags, stage nothing meaningful. A missing 'paths' key is a separate error ('Missing 'paths' parameter'); this one means the key existed but contained no usable pathspec tokens.
Source
Thrown at crates/zeroclaw-tools/src/git_operations.rs:551
working_dir: &std::path::Path,
) -> anyhow::Result<ToolResult> {
let paths = args.get("paths").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": "paths"})),
"git_operations: missing paths parameter"
);
anyhow::Error::msg("Missing 'paths' parameter")
})?;
// Validate paths against injection patterns. Returns each
// whitespace-separated pathspec as its own argument so the join is
// not handed to git as a single literal path.
let sanitized = self.sanitize_git_args(paths)?;
if sanitized.is_empty() {
anyhow::bail!("No paths to stage");
}
let mut git_args: Vec<&str> = vec!["add", "--"];
git_args.extend(sanitized.iter().map(String::as_str));
let output = self.run_git_command(&git_args, working_dir).await;
match output {
Ok(_) => Ok(ToolResult {
success: true,
output: format!("Staged: {}", sanitized.join(" ")).into(),
error: None,
}),
Err(e) => Ok(ToolResult {
success: false,
output: ToolOutput::default(),
error: Some(format!("Add failed: {e}")),
}),View on GitHub (pinned to 88bb9c8533)
Solutions
- Pass at least one real pathspec, e.g. {"paths": "src/main.rs"} or a directory like {"paths": "crates/zeroclaw-tools"}.
- To stage everything in the working tree, pass "." explicitly: {"paths": "."} — the tool appends it after `add --` so it is treated as a literal path.
- If paths come from a computed list, skip the add call entirely when the list is empty rather than invoking the tool.
- Check for accidental whitespace-only strings from templating or env substitution before calling.
Example fix
// before
let args = serde_json::json!({ "paths": "" });
// tool bails: No paths to stage
// after
let args = serde_json::json!({ "paths": "." }); // stage all changes Defensive patterns
Strategy: validation
Validate before calling
fn build_add_args(paths: &[String]) -> Option<serde_json::Value> {
(!paths.is_empty()).then(|| serde_json::json!({ "paths": paths.join(" ") }))
} Try / catch
match tool_result {
Err(e) if e.to_string().contains("No paths to stage") => {
// nothing to stage: treat as a no-op success, not a failure
}
other => other,
} Prevention
- Skip the add call when the computed changed-file list is empty instead of joining an empty vec.
- Default 'paths' to "." when the intent is 'stage everything'.
- Split pathspecs on whitespace yourself first to confirm at least one token survives.
When it happens
Trigger: Calling git add with {"paths": ""} or {"paths": " "} — a string with no whitespace-separated tokens. Also occurs when a caller forwards a joined list that turned out empty, e.g. format!("{}", changed_files.join(" ")) on an empty vec.
Common situations: A pipeline computes changed files programmatically and passes an empty join when nothing changed; an agent calls add before any edits exist; a wrapper defaults paths to an empty string instead of "."; a path list variable is unset in config.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Commit message cannot be empty
- Invalid branch specification
- Unknown stash action: {action}. Use: push, pop, list, drop
- Missing 'subcommand' parameter. Use: list, add, remove, prun
- Missing 'worktree_path' parameter for worktree add
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/700530007c74d5e3.
Report an issue: GitHub.