oraios/serena · warning · FileExistsError

Project with path {project_root} was already added with name

Error message

Project with path {project_root} was already added with name '{already_registered_project.project_name}'.

What it means

add_project_from_path() prevents duplicate registrations: if a project with the same resolved root path is already present in self.projects, it raises FileExistsError reporting the path and the name it was registered under. Registering the same directory twice would create duplicate project entries in serena_config.yml.

Source

Thrown at src/serena/config/serena_config.py:1270

        Adds a new project to the Serena configuration from a given path, auto-generating the project
        with defaults if it does not exist.
        Will raise a FileExistsError if a project already exists at the path.

        :param project_root: the path to the project to add
        :param asynchronous_autogen: whether to use asynchronous auto-generation for the project configuration
        :return: the project that was added
        """
        from ..project import Project

        project_root = Path(project_root).resolve()
        if not project_root.exists():
            raise FileNotFoundError(f"Error: Path does not exist: {project_root}")
        if not project_root.is_dir():
            raise FileNotFoundError(f"Error: Path is not a directory: {project_root}")

        for already_registered_project in self.projects:
            if str(already_registered_project.project_root) == str(project_root):
                raise FileExistsError(
                    f"Project with path {project_root} was already added with name '{already_registered_project.project_name}'."
                )

        autogen = ProjectConfigAutoGenerationMode.ASYNCHRONOUS if asynchronous_autogen else ProjectConfigAutoGenerationMode.SYNCHRONOUS
        project_config = ProjectConfig.load(project_root, serena_config=self, autogen=autogen)

        new_project = Project(
            project_root=str(project_root),
            project_config=project_config,
            is_newly_created=True,
            serena_config=self,
        )
        self.add_registered_project(RegisteredProject.from_project_instance(new_project))

        return new_project

    def remove_project(self, project_name: str) -> None:
        # find the index of the project with the desired name and remove it

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Before adding, scan config.projects for an entry whose project_root matches the resolved path and reuse it (get_registered_project(path)) instead of adding.
  2. Catch FileExistsError and treat it as success: fetch the existing project via get_registered_project(project_root).
  3. Remove the existing registration first with remove_project(existing.project_name) if you intend to re-add it fresh.

Example fix

// before
config.add_project_from_path('/repos/app')  # FileExistsError on rerun
// after
try:
    config.add_project_from_path('/repos/app')
except FileExistsError:
    project = config.get_registered_project('/repos/app')
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
resolved = str(Path(project_root).resolve())
already = any(str(p.project_root) == resolved for p in config.projects)

Type guard

def is_registered(config, root) -> bool:
    from pathlib import Path
    r = str(Path(root).resolve())
    return any(str(p.project_root) == r for p in config.projects)

Try / catch

try:
    config.add_project_from_path(project_root)
except FileExistsError:
    project = config.get_registered_project(project_root)  # reuse existing

Prevention

When it happens

Trigger: Calling add_project_from_path('/repos/app') when '/repos/app' (or a path string that resolves identically) is already registered — including calling activate_project_from_path_or_name() with an already-registered path.

Common situations: Re-running an onboarding/activation script without idempotency; two code paths both adding the project during startup; equivalent paths like /repos/app vs /repos/../repos/app resolving to the same root (resolve() normalizes them).

Related errors


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