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
- Perform the write outside tool context: call the API with is_tool_context=False from non-tool code.
- Adjust read_only_memory_patterns in the Serena config if the memory should be tool-writable.
- Have a human edit the memory file directly rather than through the tool context.
- 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
- Keep a manifest of read-only memory names and skip them in agent write workflows
- Review read_only_memory_patterns when adding new protected memories
- Surface read-only status to the agent in prompts to avoid wasted write attempts
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
- Memory '{name}' matches an ignored_memory_patterns pattern a
- Context file not found: {path.resolve()}
- Cannot use both fixed_tools and excluded_tools/included_opti
- Unknown language backend '{backend_str}': valid values are {
- Invalid line_ending: {value!r}. Valid values are: {valid}
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/2bc9e802b0cca28a.
Report an issue: GitHub.