oraios/serena · error · FileNotFoundError
Relative path {relative_path} does not exist.
Error message
Relative path {relative_path} does not exist. What it means
_collect_files (used by replace_content's scope collection) validates that the given relative path exists under the project root after ignore-rule validation. If it does not exist, a FileNotFoundError is raised before any matching or replacement happens.
Source
Thrown at src/serena/tools/file_tools.py:327
)
ambiguous = [o for o in occurrences if o.is_ambiguous]
if ambiguous:
listing = self._render_listing(replacer, occurrences, contents, max_answer_chars, dry_run=False)
raise ValueError(
f"{len(ambiguous)} occurrence(s) are ambiguous (the pattern matches again inside the matched text, "
f"indicating possible over-matching) - NO changes were applied. Review the prospective changes below "
f"and either refine the pattern or explicitly select occurrences via occurrence_ids.\n{listing}"
)
return self._apply_occurrences(replacer, occurrences, contents, needle, repl)
def _collect_files(self, relative_path: str, paths_include_glob: str, paths_exclude_glob: str) -> list[tuple[str, str]]:
"""Collects (relative_path, content) pairs of the non-ignored files in scope, in sorted path order."""
relative_path = relative_path.strip()
if relative_path:
self.project.validate_relative_path(relative_path, require_not_ignored=True)
abs_path = os.path.join(self.get_project_root(), relative_path)
if not os.path.exists(abs_path):
raise FileNotFoundError(f"Relative path {relative_path} does not exist.")
if os.path.isfile(abs_path):
rel_paths = [relative_path]
else:
_dirs, rel_paths = scan_directory(
path=abs_path,
recursive=True,
is_ignored_dir=self.project.is_ignored_path,
is_ignored_file=self.project.is_ignored_path,
relative_to=self.get_project_root(),
)
include_glob_matcher = GlobMatcher(paths_include_glob.strip()) if paths_include_glob.strip() else None
exclude_glob_matcher = GlobMatcher(paths_exclude_glob.strip()) if paths_exclude_glob.strip() else None
files: list[tuple[str, str]] = []
for path in sorted(rel_paths):
if include_glob_matcher and not include_glob_matcher.matches(path):
continue
if exclude_glob_matcher and exclude_glob_matcher.matches(path):
continueView on GitHub (pinned to 7fcbca7e62)
Solutions
- Correct the relative path (relative to the project root, forward slashes) and retry
- Verify existence with os.path.exists(os.path.join(project_root, relative_path)) before the call
- List available files (e.g. via search_for_pattern or directory listing) to find the right path
- If the file should exist, restore it (git checkout) — it may have been deleted by a previous edit
Example fix
// before agent.replace_content(needle="foo", repl="bar", path="src/ap.py") // after rel = "src/app.py" assert os.path.exists(os.path.join(project_root, rel)), rel agent.replace_content(needle="foo", repl="bar", path=rel)
Defensive patterns
Strategy: validation
Validate before calling
import os
abs_path = os.path.join(project_root, relative_path)
if not os.path.exists(abs_path):
raise FileNotFoundError(abs_path)
agent.replace_content(needle, repl, path=relative_path) Type guard
def path_exists(rel: str, root: str) -> bool:
return os.path.exists(os.path.join(root, rel.strip())) Try / catch
try:
agent.replace_content(needle, repl, path=rel)
except FileNotFoundError as e:
if "does not exist" in str(e):
rel = find_correct_path(rel) # list/search project files
agent.replace_content(needle, repl, path=rel)
else:
raise Prevention
- Keep paths project-relative with forward slashes
- Re-verify paths after automated moves/renames
- List project files to confirm path spelling before edits
When it happens
Trigger: Passing path="missing/dir" or a typo'd file name to replace_content; passing an empty-string path that normalizes to project root but with a stripped/wrong value; referencing a path that is gitignored or outside the validated project root (caught earlier by validate_relative_path).
Common situations: Path separators mismatch (Windows-style backslashes on Linux); the file was moved/renamed by a prior automated edit; passing an absolute path where only project-relative paths are accepted.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Specified a relative working directory ({cwd}), but the resu
- Error: Path does not exist: {project_root}
- Error: Path is not a directory: {project_root}
- {relative_path=} points outside the project root ({self.proj
- Expected a file path, but got a directory path: {relative_pa
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/6d683f79b40372c9.
Report an issue: GitHub.