shareAI-lab/learn-claude-code · error · ValueError
Invalid memory filename: {filename}
Error message
Invalid memory filename: {filename} What it means
Raised by memory_path() in s09_memory/code.py when the supplied filename contains a path separator — Path(filename).name != filename detects any directory component. Filenames must be bare names because memory records are stored flat inside MEMORY_DIR; a separator would allow writing outside the store. Both '../' traversal and innocent subdirectory paths like 'notes/2024.md' are rejected.
Source
Thrown at s09_memory/code.py:90
return {}, text
parts = text.split("---", 2)
if len(parts) < 3:
return {}, text
try:
metadata = yaml.safe_load(parts[1]) or {}
except yaml.YAMLError:
return {}, text
if not isinstance(metadata, dict):
return {}, text
return metadata, parts[2].lstrip()
def memory_slug(name: str) -> str:
slug = re.sub(r"[^\w]+", "-", name.lower()).strip("-_")
return slug or "memory"
def memory_path(filename: str, allow_index: bool = False) -> Path:
if Path(filename).name != filename:
raise ValueError(f"Invalid memory filename: {filename}")
if filename == MEMORY_INDEX.name and not allow_index:
raise ValueError("The memory index is not a memory record")
root = MEMORY_DIR.resolve()
if not root.is_relative_to(WORKDIR.resolve()):
raise ValueError("Memory directory escapes the workspace")
path = (root / filename).resolve()
if not path.is_relative_to(root):
raise ValueError(f"Memory path escapes the store: {filename}")
return path
def _memory_slug(name: str) -> str:
return memory_slug(name)
def _normalized_memory_text(value: str) -> str:
return " ".join(value.lower().split())
def should_store_memory(candidate: dict, existing: list[dict]) -> bool:View on GitHub (pinned to 985456f4ad)
Solutions
- Flatten the name: use memory_slug() or manual replacement of '/' with '-' to get a bare filename
- Store only the record name; if you need hierarchy, encode it in the name ('notes-2024.md')
- Validate with Path(f).name == f before calling the memory tool
Example fix
// before memory_write(filename="notes/2024-08.md", ...) // after memory_write(filename="notes-2024-08.md", ...)
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def flat_filename(name: str) -> str:
return Path(name).name if Path(name).name == name else name.replace('/', '-').replace('\\', '-')
assert Path(fn).name == fn, 'filename must be bare (no directories)'
memory_write(filename=flat_filename(user_name), ...) Type guard
def is_flat_filename(filename: object) -> bool:
return isinstance(filename, str) and bool(filename) and Path(filename).name == filename Try / catch
try:
memory_path(fn)
except ValueError as e:
if 'Invalid memory filename' in str(e):
fn = fn.replace('/', '-')
memory_path(fn)
else:
raise Prevention
- Store records as flat names; encode hierarchy with dashes
- Run memory_slug() over free-form names before use
- Never pass directory listings or absolute paths as memory filenames
When it happens
Trigger: Calling a memory tool with filename="../index.py", filename="subdir/note.md", or an absolute path "/tmp/x.md" (its .name differs). On Windows, backslash-containing names also fail this check.
Common situations: LLMs trying to organize memories into folders; paths copied wholesale from other tool output; traversal attempts by prompt-injected content reaching the memory tool.
Related errors
- Memory directory escapes the workspace
- Memory path escapes the store: {filename}
- Tasks directory escapes workspace
- Path escapes workspace: {path}
- Path escapes workspace: {p}
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/ee352ecbf2df3d2f.
Report an issue: GitHub.