Hmbown/CodeWhale · error
must be a single path component
Error message
{kind} must be a single path component What it means
ensure_safe_storage_id rejects values that are not exactly one normal path component — containing '/', '\\', '..' or similar — to prevent path traversal or nested storage paths. It throws '{kind} must be a single path component' when the value has multiple components or a non-Normal component (RootDir, CurDir, ParentDir, Prefix).
Solutions
- Sanitize the id: strip or replace path separators and reject '..' before calling the API (see sanitize_filename in the same file).
- Generate ids internally (UUID/ULID) instead of accepting raw external strings.
- Keep this rejection — do not work around it; it is a deliberate path-traversal guard.
Example fix
// before manager.store_task(&user_input, task).await?; // user_input = "../evil" // after let safe = sanitize_filename(&user_input); manager.store_task(&safe, task).await?;
Defensive patterns
Strategy: validation
Validate before calling
fn is_safe_id(value: &str) -> bool {
!value.is_empty()
&& !value.contains(['/', '\\'])
&& value != "." && value != ".."
} Prevention
- Sanitize or hash user-supplied ids before using them as storage keys.
- Generate ids internally rather than accepting raw external strings.
- Never bypass this check — it blocks path traversal.
When it happens
Trigger: Passing an id containing a path separator or '..' (e.g. "../escape", "a/b", "C:\\x") into a storage-backed task-manager call.
Common situations: User-supplied ids echoed into storage keys; unsanitized external input; constructing ids by joining strings with '/' by mistake; attempted path-traversal via crafted task ids.
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
- must be a single path component
- unsafe bundle path
- xAI OAuth private basename must be one UTF-8 path component
- append_allow_rules only accepts action = "allow"
- bad_args
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/abd0df50bce8db47.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/task_manager.rs:3391
out.push_str("...");
return out;
}
if ch.is_control() && ch != '\n' && ch != '\t' {
continue;
}
out.push(ch);
count += 1;
}
out
}
fn ensure_safe_storage_id(kind: &str, value: &str) -> Result<()> {
let mut components = Path::new(value).components();
let Some(component) = components.next() else {
bail!("{kind} must not be empty");
};
if components.next().is_some() || !matches!(component, std::path::Component::Normal(_)) {
bail!("{kind} must be a single path component");
}
Ok(())
}
fn sanitize_filename(input: &str) -> String {
let mut out = String::new();
for ch in input.chars() {
if ch.is_ascii_alphanumeric() || ch == '_' || ch == '-' {
out.push(ch);
} else {
out.push('_');
}
}
if out.is_empty() {
"artifact".to_string()
} else {
out
}View on GitHub (pinned to 73e0f67d83)