zeroclaw-labs/zeroclaw · error · anyhow::Error
Worktree path '{}' resolves outside the workspace or allowed
Error message
Worktree path '{}' resolves outside the workspace or allowed roots What it means
Before creating a worktree, ensure_worktree_add_target_allowed resolves the target's parent directory (which must already exist, because canonicalize fails on missing paths), re-joins the file name, and asks SecurityPolicy::is_resolved_path_allowed whether the resolved target is inside the workspace root or one of the policy's allowed_roots (git_operations.rs:165-172; policy check at zeroclaw-config/src/policy.rs:3056). If the location is outside every allowlisted root, the add is refused.
Source
Thrown at crates/zeroclaw-tools/src/git_operations.rs:168
::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!({
"parent": parent.display().to_string(),
"error": format!("{}", e),
})),
"git_operations: cannot resolve worktree parent"
);
anyhow::Error::msg(format!(
"Cannot resolve worktree parent '{}': {e}",
parent.display()
))
})?;
let resolved_target = resolved_parent.join(file_name);
if !self.security.is_resolved_path_allowed(&resolved_target) {
anyhow::bail!(
"Worktree path '{}' resolves outside the workspace or allowed roots",
raw_path
);
}
Ok(resolved_target)
}
fn ensure_worktree_remove_target_allowed(&self, raw_path: &str) -> anyhow::Result<PathBuf> {
let candidate = self.candidate_path(raw_path)?;
let resolved = candidate.canonicalize().map_err(|e| {
::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!({
"raw_path": raw_path,
"error": format!("{}", e),View on GitHub (pinned to 88bb9c8533)
Solutions
- Create worktrees under the workspace root (e.g. ".worktrees/name") — always allowed.
- Create the parent directory first so canonicalize succeeds, keeping it under the workspace.
- If an external location is genuinely required, add its canonical parent directory to the SecurityPolicy allowed_roots in zeroclaw config and retry.
- Pre-check with security.is_resolved_path_allowed on the caller side before issuing the add.
Example fix
// before worktree(op: "add", path: "/tmp/feature-wt") // -> Worktree path '/tmp/feature-wt' resolves outside the workspace or allowed roots // after worktree(op: "add", path: ".worktrees/feature-wt")
Defensive patterns
Strategy: validation
Validate before calling
// Verify the target would pass the policy before calling the tool.
let candidate = workspace.join(".worktrees").join(name);
std::fs::create_dir_all(candidate.parent().unwrap())?; // parent must exist
let resolved_parent = candidate.parent().unwrap().canonicalize()?;
let target = resolved_parent.join(candidate.file_name().unwrap());
if !security.is_resolved_path_allowed(&target) {
return Err(format!("worktree target {target:?} outside allowed roots"));
} Type guard
fn is_allowed_worktree_target(target: &std::path::Path, security: &SecurityPolicy) -> bool {
security.is_resolved_path_allowed(target)
} Try / catch
match git_tool.execute(params).await {
Err(e) if e.to_string().contains("resolves outside the workspace or allowed roots") => {
// create the worktree under the workspace instead and retry; widen
// allowed_roots only as a deliberate, reviewed config change
}
r => r,
} Prevention
- Standardize on a .worktrees/ directory inside the workspace
- Create the parent directory before requesting worktree add
- Keep SecurityPolicy allowed_roots minimal and explicit
- Pre-check targets with security.is_resolved_path_allowed when you hold the policy handle
When it happens
Trigger: Calling git_worktree add with a target outside the workspace, e.g. "/tmp/wt" or "~/wt" (broad default-forbidden roots include /home and /tmp per policy.rs comments); targeting a sibling directory of the workspace; targeting a path whose parent does not exist yet (fails first with 'Cannot resolve worktree parent'); running under a workspace_only security policy with no extra allowed_roots configured.
Common situations: Developers following the `git worktree add ../branch-x` convention inside a sandboxed agent workspace; CI sandboxes where the workspace is a subdirectory; policies tightened to workspace_only during a security review so previously fine locations stop working.
Related errors
- Path '{}' resolves outside the workspace directory
- Workspace path {} is not in runtime.docker.allowed_workspace
- Path not allowed: contains null byte
- Path not allowed: parent-directory traversal is not allowed
- Lark/Feishu marker target resolves outside workspace_dir
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/20b9d937f91d060c.
Report an issue: GitHub.