oraios/serena · error · ValueError
Tool '{req.tool_name}' is not read-only and cannot be execut
Error message
Tool '{req.tool_name}' is not read-only and cannot be executed via the query_project route What it means
ProjectServer's query_project route is restricted to read-only tools. Before applying the requested tool it checks tool.is_readonly(), and mutating tools (editors, shell executors, etc.) are rejected to keep the server side-effect free for concurrent queries.
Source
Thrown at src/serena/project_server.py:133
project.create_language_server_manager()
with self._loaded_projects_lock:
self._loaded_projects_by_root[key] = project
return project
def _query_project(self, req: QueryProjectRequest) -> str:
"""Handle a /query_project request by invoking the agent on the specified project and tool.
The active project is process-wide state, whereas ``apply_ex`` runs the tool on the
agent's task executor thread. Without the lock, a second request entering
``active_project_context`` while the first request's tool is still executing would
redirect that tool to the wrong project (and restore the wrong project afterwards).
"""
project = self._get_project(req.project_name)
with self._active_project_lock, self._agent.active_project_context(project):
tool = self._agent.get_tool_by_name(req.tool_name)
if not tool.is_readonly():
raise ValueError(f"Tool '{req.tool_name}' is not read-only and cannot be executed via the query_project route")
params = json.loads(req.tool_params_json)
return tool.apply_ex(**params)
def run(self) -> None:
"""
Run the server on the given host and port.
"""
from flask import cli
# suppress the default Flask startup banner
# ty cannot model reassigning a third-party module's function attribute (it rejects any
# replacement, even one with an identical signature), so the monkeypatch is suppressed here
cli.show_server_banner = lambda *args, **kwargs: None # ty: ignore[invalid-assignment]
self._app.run(host=self._host, port=self._port, debug=False, use_reloader=False, threaded=True)
class ProjectServerClient:View on GitHub (pinned to 7fcbca7e62)
Solutions
- Use a read-only tool for query_project (find_symbol, find_referencing_symbols, etc.)
- Apply edits through the interactive Serena agent/session instead of the ProjectServer query route
- If you own the tool, ensure is_readonly() correctly reflects its behavior rather than weakening this check
Example fix
// before
server.query_project("my-repo", "replace_symbol_body", params)
// after
server.query_project("my-repo", "find_symbol", params) # read-only only Defensive patterns
Strategy: validation
Validate before calling
tool = agent.get_tool_by_name(tool_name)
if not tool.is_readonly():
raise ValueError(f"{tool_name} must be run via the interactive agent, not query_project") Type guard
def is_readonly_tool(agent, tool_name: str) -> bool:
return agent.get_tool_by_name(tool_name).is_readonly() Try / catch
try:
return server.query_project(project, tool_name, params)
except ValueError as e:
if "not read-only" in str(e):
return run_via_interactive_agent(project, tool_name, params)
raise Prevention
- Keep a whitelist of read-only tool names for query_project clients
- Route all mutating operations through the interactive agent/session
- Don't override is_readonly() on custom tools unless they truly have no side effects
When it happens
Trigger: Calling query_project with tool_name set to a write tool such as replace_symbol_body, insert_after_symbol, delete_symbol, or execute_shell_command; passing a tool whose readonly flag is misconfigured.
Common situations: Reusing client code that worked against the full agent toolset but now targets the read-only ProjectServer; attempting quick fixes through the query endpoint instead of the interactive agent.
Related errors
- Project '{project_root_or_name}' is not registered with Sere
- Body start position is not defined for {self}
- Body end position is not defined for {self}
- Body line numbers could not be determined for {self.get_name
- No symbol matching '{name_path_pattern}' found
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/a9b2b3cc0c67a433.
Report an issue: GitHub.