oraios/serena · error · ValueError

Expected a file path, but got a directory: {relative_path}

Error message

Expected a file path, but got a directory: {relative_path}

What it means

get_language_server selects a language server by file path when multiple servers are managed. Because language selection requires a file extension/name, passing a directory raises ValueError. A single-server manager bypasses the check and returns the default server for any input.

Source

Thrown at src/serena/ls_manager.py:177

    def _ensure_functional_ls(self, ls: SolidLanguageServer) -> SolidLanguageServer:
        if not ls.is_running():
            log.warning(f"Language server for language {ls.ls_id} is not running; restarting ...")
            ls = self.restart_language_server(ls.ls_id)
        return ls

    def _get_suitable_language_server(self, relative_path: str) -> SolidLanguageServer | None:
        """:param relative_path: relative path to a file"""
        for candidate in self._language_servers.values():
            if not candidate.is_ignored_path(relative_path, ignore_unsupported_files=True):
                return candidate
        return None

    def get_language_server(self, relative_path: str) -> SolidLanguageServer:
        """:param relative_path: relative path to a file"""
        ls: SolidLanguageServer | None = None
        if len(self._language_servers) > 1:
            if os.path.isdir(relative_path):
                raise ValueError(f"Expected a file path, but got a directory: {relative_path}")
            ls = self._get_suitable_language_server(relative_path)
        if ls is None:
            ls = self._default_language_server
        return self._ensure_functional_ls(ls)

    def _create_and_start_language_server(self, ls_id: LanguageServerId) -> SolidLanguageServer:
        if self._language_server_factory is None:
            raise ValueError(f"No language server factory available to create language server for {ls_id}")
        language_server = self._language_server_factory.create_language_server(ls_id)
        language_server.start()
        self._language_servers[ls_id] = language_server
        return language_server

    def restart_language_server(self, language: LanguageServerId) -> SolidLanguageServer:
        """
        Forces recreation and restart of the language server for the given language.
        It is assumed that the language server for the given language is no longer running.

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Pass an individual file path instead of a directory
  2. Resolve a representative file inside the directory before calling
  3. Check os.path.isdir(path) first and route directories to directory-aware APIs

Example fix

// before
ls = manager.get_language_server("src/utils")
// after
path = "src/utils"
if os.path.isdir(path):
    path = next(f for f in Path(path).iterdir() if f.is_file())
ls = manager.get_language_server(str(path))
Defensive patterns

Strategy: validation

Validate before calling

import os
if os.path.isdir(relative_path):
    raise ValueError(f"pass a file, not a directory: {relative_path}")

Type guard

def is_file_path(p: str) -> bool:
    return os.path.isfile(p)

Try / catch

try:
    ls = manager.get_language_server(path)
except ValueError as e:
    if "Expected a file path, but got a directory" in str(e):
        path = str(next(Path(path).rglob("*")
                    .__iter__().__class__ and Path(path).iterdir()))
        ls = manager.get_language_server(next(
            str(f) for f in Path(path).iterdir() if f.is_file()))
    else:
        raise

Prevention

When it happens

Trigger: Calling get_language_server("src/") or any directory path while the manager runs more than one language server.

Common situations: Tooling iterates directories and passes folder paths instead of file paths; code written when the project had one language later runs in a multi-language project where the directory check activates.

Related errors


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