oraios/serena · error · ValueError
{relative_path=} points outside the project root ({self.proj
Error message
{relative_path=} points outside the project root ({self.project_root}) What it means
Raised by Project.validate_relative_path (src/serena/project.py:341) when a given relative path escapes the project root — i.e. is_path_in_project() is False. It prevents file operations (apply, file collection) from touching anything outside the project sandbox.
Source
Thrown at src/serena/project.py:341
if require_file:
return exists and abs_path.is_file()
else:
return exists
def validate_relative_path(self, relative_path: str, require_not_ignored: bool = False) -> None:
"""
Validates that the given relative path is within the project directory
(and, optionally, not ignored according to the project's ignore settings),
raising a ValueError if the validation fails.
:param relative_path: the path to validate, relative to the project root
:param require_not_ignored: if True, the path must not be ignored according to the project's ignore settings
"""
if FileProxy.is_external_path(relative_path):
return
if not self.is_path_in_project(relative_path):
raise ValueError(f"{relative_path=} points outside the project root ({self.project_root})")
if require_not_ignored:
if self.is_ignored_path(relative_path):
raise ValueError(f"Path {relative_path} is ignored")
def gather_source_files(self, relative_path: str = "") -> list[str]:
"""Retrieves relative paths of all source files, optionally limited to the given path
:param relative_path: if provided, restrict search to this path
"""
rel_file_paths = []
start_path = os.path.join(self.project_root, relative_path)
if not os.path.exists(start_path):
raise FileNotFoundError(f"Relative path {start_path} not found.")
if os.path.isfile(start_path):
return [relative_path]
else:
for root, dirs, files in os.walk(start_path, followlinks=True):View on GitHub (pinned to 7fcbca7e62)
Solutions
- Pass a path relative to the project root with no '..' components
- If you intentionally need an outside file, use the external-path API (FileProxy external paths) instead of a project-relative path
- Normalize the path (os.path.normpath) and check it stays under project_root before calling
Example fix
// before
project.validate_relative_path('../shared/config.py')
// after
rel = os.path.relpath('/abs/shared/config.py', project.project_root)
if not rel.startswith('..'):
project.validate_relative_path(rel) Defensive patterns
Strategy: validation
Validate before calling
rel = os.path.normpath(rel)
assert not rel.startswith('..') and not os.path.isabs(rel), 'path escapes project root' Try / catch
try:
project.validate_relative_path(rel, require_not_ignored=True)
except ValueError as e:
logging.error('Invalid project-relative path: %s', e)
return None Prevention
- Keep all paths relative to project root
- Reject user input containing '..'
- Be aware of symlinks pointing outside the project
- Normalize paths before validation
When it happens
Trigger: Passing paths containing '..' components, absolute paths not under project_root (and not flagged as external), or symlinks resolving outside the project to validate_relative_path, apply, or _collect_files.
Common situations: Agents constructing '../other-repo/file.py' style paths; joining user-supplied absolute paths onto project_root; symlinked directories pointing outside the repo.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Expected a file path, but got a directory path: {relative_pa
- 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}
- Invalid language server: '{orig_language_str}'.\nValid value
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/4bc1b6607b4f0ac6.
Report an issue: GitHub.