Hmbown/CodeWhale · error
Fleet task ' ' path ' ' cannot contain parent traversal
Error message
Fleet task '{task_id}' {field} path '{}' cannot contain parent traversal What it means
After component-level screening, normalize_fleet_relative_path splits the path on `/` and rejects any literal `..` segment — even ones that pass earlier checks — because a parent-traversal segment would let a write claim escape the workspace boundary. This is the defense-in-depth guard for Fleet write roots.
Solutions
- Remove the `..` segments and express the path from the repository root.
- List each target directory explicitly under writable_paths instead of traversing upward.
- If the target lies outside the workspace, move it inside or change the task's workspace.
- Trim empty/`.` segments first if the intent was a plain relative path like `./src` — write `src`.
Example fix
// before writable_paths = ["src/../../shared/out"] // after writable_paths = ["shared/out"] // if actually in-repo, or restructure
Defensive patterns
Strategy: validation
Validate before calling
if p.to_string_lossy().split('/').any(|s| s == "..") {
return Err("write paths cannot contain `..` segments");
} Prevention
- Express all write claims from the workspace root — no upward traversal.
- Add spec linting that rejects any `..` segment.
- Split out-of-workspace needs into separate workspaces, not traversals.
When it happens
Trigger: fleet_write_roots or fleet_runtime_write_roots passes a path whose segments include `..` after normalization (e.g. `src/../../escape` or `a/../b` residue), and the bail fires with the original path and the owning field name.
Common situations: Hand-written task specs using relative shorthands with `..`; generated configs concatenating prefixes that leave `..` segments; users trying to share one writable root across sibling repos via traversal.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- fleet task ' ' path ' ' cannot contain parent traversal
- Fleet task ' ' path ' ' must be one repo-relative line and…
- owned skill root escapes anchor
- audited skill path does not match owned package
- bundle path escapes the config directory via a symlink…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/0b47374331ea5a02.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/worker_runtime.rs:572
matches!(
component,
std::path::Component::ParentDir
| std::path::Component::RootDir
| std::path::Component::Prefix(_)
)
})
{
bail!(
"Fleet task '{task_id}' {field} path '{}' must be one repo-relative line and cannot escape the workspace",
path.display()
);
}
let mut segments = Vec::new();
for segment in raw.split('/') {
match segment {
"" | "." => {}
".." => {
bail!(
"Fleet task '{task_id}' {field} path '{}' cannot contain parent traversal",
path.display()
);
}
value => segments.push(value),
}
}
Ok(if segments.is_empty() {
".".to_string()
} else {
segments.join("/")
})
}
fn fleet_coordination_contracts(task_spec: &FleetTaskSpec) -> Result<Vec<String>> {
let Some(value) = task_spec.metadata.get("coordination_contracts") else {
return Ok(Vec::new());
};View on GitHub (pinned to 73e0f67d83)