Hmbown/CodeWhale · error
state subdir must not contain a root or prefix
Error message
state subdir must not contain a root or prefix: {subdir} What it means
Beyond plain absoluteness, a subdir containing a root (`/`) or platform prefix (`C:\`, UNC) component could redirect resolution outside the state root. `ensure_safe_state_subdir` inspects `Path::components()` and rejects any `RootDir` or `Prefix` component.
Solutions
- Pass a plain relative single component like `"sessions"`
- Normalize the input with a relative-path join against the state root before calling
- Strip leading separators and drive prefixes, or reject the input in your own validation first
Example fix
// before
let dir = state_dir_in("/sessions")?;
// after
let dir = state_dir_in("sessions")?; Defensive patterns
Strategy: validation
Validate before calling
use std::path::{Component, Path};
fn no_root_or_prefix(subdir: &str) -> bool {
!Path::new(subdir).components()
.any(|c| matches!(c, Component::RootDir | Component::Prefix(_)))
} Try / catch
match state_dir_in(subdir) {
Err(e) if e.to_string().contains("root or prefix") => {
// strip leading separator / drive prefix and retry
}
result => result,
} Prevention
- Sanitize platform-specific path components before use
- Test subdir inputs on Windows where prefixes are common
- Prefer string constants for subdir values over user input
When it happens
Trigger: Calling a state-path helper with a subdir that parses into `Component::RootDir` or `Component::Prefix(_)` — e.g. `"/sessions"`, `"C:sessions"`, or `"\\\\server\\share"`.
Common situations: Windows paths built with drive letters leaking into the subdir slot; strings that begin with a separator; paths copied verbatim from filesystem browsing UIs.
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
- state subdir must not be an absolute path
- state subdir must not be empty
- state subdir must not contain parent-dir (..) components
- budget baseline_receipt path changed
- Codewhale credentials directory has an unsupported component
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d008072916fafb4b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/lib.rs:5735
/// subdir string; every in-tree caller passes a hardcoded single component
/// (e.g. `"sessions"`, `"."`). This validates defensively so a future caller
/// can never traverse out of the state root via `..` components or an absolute
/// path. Nested relative paths such as `"a/b"` are permitted.
fn ensure_safe_state_subdir(subdir: &str) -> Result<()> {
if subdir.is_empty() {
bail!("state subdir must not be empty");
}
let path = std::path::Path::new(subdir);
if path.is_absolute() {
bail!("state subdir must not be an absolute path: {subdir}");
}
if path.components().any(|c| {
matches!(
c,
std::path::Component::RootDir | std::path::Component::Prefix(_)
)
}) {
bail!("state subdir must not contain a root or prefix: {subdir}");
}
if path
.components()
.any(|c| matches!(c, std::path::Component::ParentDir))
{
bail!("state subdir must not contain parent-dir (..) components: {subdir}");
}
Ok(())
}
/// Resolve a state subdirectory, preferring the CodeWhale root if
/// it already exists, otherwise falling back to the legacy root.
///
/// This is the read-path resolver: it returns the primary path when
/// migration has occurred or on a fresh install, but keeps reading
/// from the legacy path for users who haven't migrated yet.
pub fn resolve_state_dir(subdir: &str) -> Result<PathBuf> {
ensure_safe_state_subdir(subdir)?;View on GitHub (pinned to 73e0f67d83)