{"record":{"id":"9fa1b58ac82c646c","repo":"oraios/serena","slug":"expected-a-file-path-but-got-a-directory-relati","errorCode":null,"errorMessage":"Expected a file path, but got a directory: {relative_path}","messagePattern":"Expected a file path, but got a directory: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/serena/ls_manager.py","lineNumber":177,"sourceCode":"    def _ensure_functional_ls(self, ls: SolidLanguageServer) -> SolidLanguageServer:\n        if not ls.is_running():\n            log.warning(f\"Language server for language {ls.ls_id} is not running; restarting ...\")\n            ls = self.restart_language_server(ls.ls_id)\n        return ls\n\n    def _get_suitable_language_server(self, relative_path: str) -> SolidLanguageServer | None:\n        \"\"\":param relative_path: relative path to a file\"\"\"\n        for candidate in self._language_servers.values():\n            if not candidate.is_ignored_path(relative_path, ignore_unsupported_files=True):\n                return candidate\n        return None\n\n    def get_language_server(self, relative_path: str) -> SolidLanguageServer:\n        \"\"\":param relative_path: relative path to a file\"\"\"\n        ls: SolidLanguageServer | None = None\n        if len(self._language_servers) > 1:\n            if os.path.isdir(relative_path):\n                raise ValueError(f\"Expected a file path, but got a directory: {relative_path}\")\n            ls = self._get_suitable_language_server(relative_path)\n        if ls is None:\n            ls = self._default_language_server\n        return self._ensure_functional_ls(ls)\n\n    def _create_and_start_language_server(self, ls_id: LanguageServerId) -> SolidLanguageServer:\n        if self._language_server_factory is None:\n            raise ValueError(f\"No language server factory available to create language server for {ls_id}\")\n        language_server = self._language_server_factory.create_language_server(ls_id)\n        language_server.start()\n        self._language_servers[ls_id] = language_server\n        return language_server\n\n    def restart_language_server(self, language: LanguageServerId) -> SolidLanguageServer:\n        \"\"\"\n        Forces recreation and restart of the language server for the given language.\n        It is assumed that the language server for the given language is no longer running.\n","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/serena/ls_manager.py#L159-L195","documentation":"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.","triggerScenarios":"Calling get_language_server(\"src/\") or any directory path while the manager runs more than one language server.","commonSituations":"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.","solutions":["Pass an individual file path instead of a directory","Resolve a representative file inside the directory before calling","Check os.path.isdir(path) first and route directories to directory-aware APIs"],"exampleFix":"// before\nls = manager.get_language_server(\"src/utils\")\n// after\npath = \"src/utils\"\nif os.path.isdir(path):\n    path = next(f for f in Path(path).iterdir() if f.is_file())\nls = manager.get_language_server(str(path))","handlingStrategy":"validation","validationCode":"import os\nif os.path.isdir(relative_path):\n    raise ValueError(f\"pass a file, not a directory: {relative_path}\")","typeGuard":"def is_file_path(p: str) -> bool:\n    return os.path.isfile(p)","tryCatchPattern":"try:\n    ls = manager.get_language_server(path)\nexcept ValueError as e:\n    if \"Expected a file path, but got a directory\" in str(e):\n        path = str(next(Path(path).rglob(\"*\")\n                    .__iter__().__class__ and Path(path).iterdir()))\n        ls = manager.get_language_server(next(\n            str(f) for f in Path(path).iterdir() if f.is_file()))\n    else:\n        raise","preventionTips":["Ensure callers always pass file paths, never globs or directories","Resolve representative files when walking directories","Remember the check only applies when multiple language servers are active","Add path validation at the tool/agent boundary"],"tags":["language-server","path-validation","argument-error"],"backgroundTag":"file-vs-directory-path-mismatch","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}