oraios/serena · error · PermissionError

Attempted to write to read_only memory: '{name}')

Error message

Attempted to write to read_only memory: '{name}')

What it means

_check_write_access raises PermissionError when a write operation targets a memory that matches a read_only_memory_patterns regex while operating in a tool-execution context (is_tool_context=True). Read-only memories can be read but not modified by tools, protecting curated/global content from agent-driven changes.

Source

Thrown at src/serena/memories/memory_manager.py:202

            raise ValueError(f"Memory name cannot be absolute or contain empty path segments. Got: {name}")

        if self._is_global(name):
            if name == self.GLOBAL_TOPIC:
                raise ValueError(
                    f'Bare "{self.GLOBAL_TOPIC}" is not a valid memory name. Use "{self.GLOBAL_TOPIC}/<name>" to address a global memory.'
                )
            # Strip "global/" prefix and resolve against global dir
            sub_name = name[len(self.GLOBAL_TOPIC) + 1 :]
            return self._resolve_memory_path(self._global_memory_dir, sub_name.split("/"))

        # Project-local memory
        assert self._project_memory_dir is not None, "Project dir was not passed at initialization"
        return self._resolve_memory_path(self._project_memory_dir, parts)

    def _check_write_access(self, name: str, is_tool_context: bool) -> None:
        # in tool context, memories can be read-only
        if is_tool_context and self._is_read_only_memory(name):
            raise PermissionError(f"Attempted to write to read_only memory: '{name}')")

    def load_memory(self, name: str) -> str:
        name = self._sanitize_name(name)
        self._check_not_ignored(name)
        memory_file_path = self.get_memory_file_path(name)
        if not memory_file_path.exists():
            raise FileNotFoundError(f"Memory named '{name}' not found")
        with open(memory_file_path, encoding=self._encoding) as f:
            return f.read()

    def save_memory(self, name: str, content: str, is_tool_context: bool) -> str:
        name = self._sanitize_name(name)
        self._check_not_ignored(name)
        self._check_write_access(name, is_tool_context)
        memory_file_path = self.get_memory_file_path(name)
        with open(memory_file_path, "w", encoding=self._encoding) as f:
            f.write(content)
        return f"Memory {name} written."

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Perform the write outside tool context: call the API with is_tool_context=False from non-tool code.
  2. Adjust read_only_memory_patterns in the Serena config if the memory should be tool-writable.
  3. Have a human edit the memory file directly rather than through the tool context.
  4. Choose a non-protected destination name when the intent was move_memory/rename.

Example fix

// before
manager.save_memory("global/conventions", content, is_tool_context=True)
// PermissionError
// after
manager.save_memory("global/conventions", content, is_tool_context=False)  # non-tool context
# or relax config: read_only_memory_patterns = ["global/scratch/.*"]
Defensive patterns

Strategy: validation

Validate before calling

import re
if is_tool_context and any(p.fullmatch(name) for p in map(re.compile, read_only_memory_patterns)):
    raise PermissionError(f"{name} is read-only in tool context")

Type guard

def is_writable(name: str, read_only: list[re.Pattern], is_tool_context: bool) -> bool:
    return not (is_tool_context and any(p.fullmatch(name) for p in read_only))

Try / catch

try:
    manager.save_memory(name, content, is_tool_context=True)
except PermissionError:
    log.info("%s is read-only in tool context; editing outside tool context", name)
    manager.save_memory(name, content, is_tool_context=False)

Prevention

When it happens

Trigger: Calling save_memory, delete_memory, move_memory, or edit_memory with is_tool_context=True on a name that regex-fullmatches any read_only_memory_patterns entry configured on the MemoryManager.

Common situations: An agent (via write_memory/edit_memory tools) attempts to overwrite protected memories such as global conventions or system-maintained notes; a recently added read_only pattern now covers names that tools previously could edit; renaming a memory whose destination name matches a read-only pattern.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/2bc9e802b0cca28a. Report an issue: GitHub.