Hmbown/CodeWhale · error · io::Error
Fleet artifact path must stay within the workspace
Error message
Fleet artifact path must stay within the workspace
What it means
This error means the resolved Fleet artifact path escaped the workspace directory or contained illegal components (e.g. a drive colon on Windows, non-Normal components). The library throws it from invalid_path, used by WorkspaceFile::open and sibling, whenever validation of the joined path fails.
Solutions
- Sanitize the artifact name: strip path separators and reject '..' before joining
- On Windows, remove or replace any ':' in the filename
- Join relative names onto the workspace directory and verify the result stays within it before calling open
Example fix
// before
let name = format!("{}.json", user_input);
// after
let name = format!("{}.json", user_input.replace(['/', '\\', ':'], "_")); Defensive patterns
Strategy: validation
Validate before calling
fn safe_artifact_name(name: &str) -> Option<&str> {
let ok = !name.is_empty()
&& !name.contains('..')
&& !name.contains('/')
&& !name.contains('\\')
&& !(cfg!(windows) && name.contains(':'));
ok.then_some(name)
} Try / catch
match WorkspaceFile::open(dir, name, write) {
Ok(f) => use_file(f),
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
eprintln!("artifact name escaped workspace or contains illegal characters");
}
Err(e) => return Err(e.into()),
} Prevention
- Treat artifact names as untrusted: strip separators, '..' and ':' before joining
- Always join names onto a fixed workspace dir and canonicalize to verify containment
- Never build Fleet paths from raw user input
When it happens
Trigger: Passing a filename containing '..' or absolute components, or on Windows a name containing a ':' (alternate data stream / drive letter), to Fleet artifact open/sibling APIs.
Common situations: Building artifact names from untrusted or user-supplied input containing path separators or '..'; Windows filenames with a colon intended as a timestamp; misconfigured artifact directory.
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
- config path cannot contain '..' components
- agent profile cannot be empty
- agent profile must be a simple token
- agent profile model must be a visible model id without…
- agent profile path is not a directory
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/fb016bebb2757a76.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/files.rs:16
//! Workspace-confined file operations shared by Fleet artifacts and its ledger.
use std::fs::File;
use std::io::{self, Write};
use std::path::{Component, Path};
pub(crate) fn path_is_confined(path: &Path) -> bool {
!path.as_os_str().is_empty()
&& path.components().all(|component| match component {
Component::Normal(name) => !cfg!(windows) || !name.as_encoded_bytes().contains(&b':'),
_ => false,
})
}
fn invalid_path() -> io::Error {
io::Error::new(
io::ErrorKind::InvalidInput,
"Fleet artifact path must stay within the workspace",
)
}
#[cfg(unix)]
#[derive(Debug)]
pub(crate) struct WorkspaceFile {
directory: File,
filename: std::ffi::CString,
}
#[cfg(unix)]
impl WorkspaceFile {
pub(crate) fn open(workspace: &Path, relative: &Path, create: bool) -> io::Result<Self> {
use std::os::fd::{AsRawFd, FromRawFd};
use std::os::unix::ffi::OsStrExt;
if !path_is_confined(relative) {View on GitHub (pinned to 73e0f67d83)