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

  1. Flatten the name: use memory_slug() or manual replacement of '/' with '-' to get a bare filename
  2. Store only the record name; if you need hierarchy, encode it in the name ('notes-2024.md')
  3. 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

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


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/ee352ecbf2df3d2f. Report an issue: GitHub.