Hmbown/CodeWhale · error
Fleet task ' ' path ' ' must be one repo-relative line and…
Error message
Fleet task '{task_id}' {field} path '{}' must be one repo-relative line and cannot escape the workspace What it means
normalize_fleet_relative_path rejects a declared Fleet write path that is not a clean repo-relative path: if the raw path contains a ParentDir, RootDir, or Prefix component (absolute path, drive prefix, or leading `..`), it cannot be contained inside the workspace and the task fails. Write claims must each be a single repo-relative line so the runtime can bound them under the workspace root.
Solutions
- Replace the absolute path with a path relative to the repository root (e.g. `src/module/`).
- Remove any `..` traversal; enumerate the actual in-repo directories you need instead.
- Strip drive-letter/UNC prefixes from Windows-style entries and re-express them relative to the workspace.
- If you truly need out-of-workspace writes, restructure the task or workspace rather than escaping the claim.
Example fix
// before writable_paths = ["/home/me/repo/src", "../shared"] // after writable_paths = ["src"]
Defensive patterns
Strategy: validation
Validate before calling
fn is_clean_relative(p: &Path) -> bool {
!p.is_absolute()
&& p.components().all(|c| !matches!(c, Component::ParentDir | Component::RootDir | Component::Prefix(_)))
} Prevention
- Author writable_paths strictly relative to the repo root.
- Never use absolute or Windows-style paths in fleet configs.
- Lint task specs for `..` and leading `/` before submission.
When it happens
Trigger: fleet_write_roots or fleet_runtime_write_roots calls normalize_fleet_relative_path with a path like `/etc/passwd`, `C:\repo\src`, `../sibling/`, or `../../out`, producing this error with field naming which claim (writable_paths or runtime write root) was rejected.
Common situations: Pasting an absolute path from the host into writable_paths; using `..` to reach a sibling repo from a fleet task; Windows-authored configs with drive-letter prefixes checked into a repo used on Linux.
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 ' ' cannot contain parent traversal
- fleet task ' ' path ' ' must be one repo-relative line and…
- 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/971081540886ae97.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/worker_runtime.rs:562
fn normalize_fleet_relative_path(
path: &std::path::Path,
task_id: &str,
field: &str,
) -> Result<String> {
let raw = path.to_string_lossy().replace('\\', "/");
if raw.chars().any(|ch| matches!(ch, '\0' | '\r' | '\n'))
|| path.is_absolute()
|| path.components().any(|component| {
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() {View on GitHub (pinned to 73e0f67d83)