Hmbown/CodeWhale · error
invalid memory workspace id
Error message
invalid memory workspace id
What it means
safe_component sanitizes strings used as filesystem path components (workspace ids). A value that is empty, '.', '..', or contains '/' or '\' could escape or corrupt the memory directory, so the function refuses it. This is a path-traversal guard applied to every workspace id before it becomes a directory name.
Solutions
- Sanitize the workspace id: strip or replace path separators and reject '.'/'..' before calling
- Derive the id from a safe slug (alphanumeric, dash, underscore) of the original name
- Reject the value upstream in config parsing so an invalid id never reaches workspace_path
Example fix
// before
let ws = user_supplied_name; // "team/sub"
memory.write(ws, note)
// after
let ws = user_supplied_name.replace(['/', '\\'], "-");
if ws.is_empty() || ws == "." || ws == ".." { return Err("bad workspace id"); }
memory.write(ws, note) Defensive patterns
Strategy: validation
Validate before calling
fn is_safe_component(v: &str) -> bool {
!(v.is_empty() || v == "." || v == ".." || v.contains('/') || v.contains('\\'))
} Type guard
fn safe_workspace_id(v: &str) -> Option<&str> {
if v.is_empty() || v == "." || v == ".." || v.contains('/') || v.contains('\\') { None } else { Some(v) }
} Try / catch
match memory.workspace_path(id) {
Ok(path) => path,
Err(e) if e.to_string().contains("invalid memory workspace id") => {
return Err(anyhow!("workspace id '{}' contains path separators", id))
}
Err(e) => return Err(e),
} Prevention
- Slugify user-provided workspace names (allow [A-Za-z0-9_-] only)
- Validate workspace ids at config-load time, not just at filesystem use
- Never construct workspace ids by joining raw user input with separators
When it happens
Trigger: Calling workspace_path (directly or via memory APIs taking a workspace id) with an id that is empty, equals '.' or '..', or embeds a slash or backslash character.
Common situations: Workspace ids derived from untrusted or user-supplied names like 'team/sub'; Windows-style paths 'a\\b' reaching validation; default/placeholder ids left as '.'; empty id from a missing config field.
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
- bad_args
- config path cannot contain '..' components
- Fleet artifact path must stay within the workspace
- must be a single path component
- must be a single path component
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/694dfa3fa2fbdcf1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/native_memory.rs:911
Ok(note.trim_start_matches('-').trim().to_string())
}
fn validate_query(query: &str) -> Result<&str> {
let query = query.trim();
if query.is_empty() || query.chars().count() > MAX_QUERY_CHARS {
bail!("memory search query is empty or too long");
}
Ok(query)
}
fn safe_component(value: &str) -> Result<String> {
if value.is_empty()
|| value == "."
|| value == ".."
|| value.contains('/')
|| value.contains('\\')
{
bail!("invalid memory workspace id");
}
Ok(value.to_string())
}
fn ensure_memory_file(path: &Path) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
if !path.exists() {
File::create(path)?;
}
Ok(())
}
fn file_mtime(path: &Path) -> Result<i64> {
Ok(fs::metadata(path)?
.modified()?
.duration_since(UNIX_EPOCH)View on GitHub (pinned to 433685b202)