zeroclaw-labs/zeroclaw · error · anyhow::Error
Path not allowed: contains null byte
Error message
Path not allowed: contains null byte
What it means
candidate_path, the shared pre-check for worktree add and remove targets, rejects any raw_path containing a NUL byte (git_operations.rs:109-110). A NUL cannot appear in a legal filesystem path and is the classic marker of corrupted input — a truncated C string, a binary blob leaked into JSON, or an LLM emitting \u0000 — so it is refused before any filesystem access happens.
Source
Thrown at crates/zeroclaw-tools/src/git_operations.rs:110
anyhow::Error::msg(format!("Cannot resolve path '{}': {}", p, e))
})?;
let workspace_canonical = self
.workspace_dir
.canonicalize()
.unwrap_or_else(|_| self.workspace_dir.clone());
if !resolved.starts_with(&workspace_canonical) {
anyhow::bail!("Path '{}' resolves outside the workspace directory", p);
}
resolved
}
_ => self.workspace_dir.clone(),
};
Ok(base)
}
fn candidate_path(&self, raw_path: &str) -> anyhow::Result<PathBuf> {
if raw_path.contains('\0') {
anyhow::bail!("Path not allowed: contains null byte");
}
if Path::new(raw_path)
.components()
.any(|c| matches!(c, std::path::Component::ParentDir))
{
anyhow::bail!("Path not allowed: parent-directory traversal is not allowed");
}
let raw = Path::new(raw_path);
Ok(if raw.is_absolute() {
raw.to_path_buf()
} else {
self.workspace_dir.join(raw)
})
}
fn ensure_worktree_add_target_allowed(&self, raw_path: &str) -> anyhow::Result<PathBuf> {
let candidate = self.candidate_path(raw_path)?;View on GitHub (pinned to 88bb9c8533)
Solutions
- Sanitize the path upstream: strip or reject control characters before the tool call.
- Fix the source of the string — usually JSON decoding or buffer slicing that let \u0000 through.
- Re-issue the worktree call with a clean, relative path under the workspace.
Example fix
// before worktree(op: "add", path: ".worktrees/feat\u0000") // -> Path not allowed: contains null byte // after worktree(op: "add", path: ".worktrees/feat")
Defensive patterns
Strategy: validation
Validate before calling
fn path_is_clean(raw: &str) -> bool {
!raw.contains('\0')
}
assert!(path_is_clean(worktree_path), "worktree path contains a null byte"); Type guard
fn path_is_clean(raw: &str) -> bool { !raw.contains('\0') } Try / catch
match git_tool.execute(params).await {
Err(e) if e.to_string().contains("contains null byte") => {
// input corruption: strip control characters and retry once with the
// sanitized string; if another NUL appears, reject the input source
}
r => r,
} Prevention
- Validate strings decoded from JSON or fuzzed sources before they reach tool args
- Reject all control characters (not just NUL) in path inputs at the API boundary
- Treat NUL bytes as a security signal: log the originating request, not just the path
When it happens
Trigger: Calling the git tool's worktree operation with a path string that embeds a NUL, such as ".worktrees/feat\u0000", a value decoded from malformed JSON with embedded control characters, or a path copied from a buffer that was not NUL-terminated and sliced past its end.
Common situations: Prompt-injection or fuzzing payloads reaching tool args; deserialized JSON where \u0000 survived into a Rust String; copy-paste from logs containing binary garbage; downstream systems that build paths from fixed-size buffers.
Related errors
- Path not allowed: parent-directory traversal is not allowed
- Worktree path '{}' resolves outside the workspace or allowed
- Missing 'subcommand' parameter. Use: list, add, remove, prun
- Missing 'worktree_path' parameter for worktree add
- Missing 'worktree_path' parameter for worktree remove
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/0b314b4a3eb8a74a.
Report an issue: GitHub.