oraios/serena · error · ValueError

Language server for language {ls_id.value} already present

Error message

Language server for language {ls_id.value} already present

What it means

add_language_server refuses duplicates: if a server for the requested language is already managed, it raises ValueError rather than replacing it. To replace a server, remove_language_server must be called first.

Source

Thrown at src/serena/ls_manager.py:211

        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.

        :param language: the language
        :return: the newly created language server
        """
        if language not in self._language_servers:
            raise ValueError(f"No language server for language {language.value} present; cannot restart")
        return self._create_and_start_language_server(language)

    def add_language_server(self, ls_id: LanguageServerId) -> SolidLanguageServer:
        """
        Dynamically adds a new language server for the given language.

        :param ls_id: the language server to add
        :return: the newly created language server
        """
        if ls_id in self._language_servers:
            raise ValueError(f"Language server for language {ls_id.value} already present")
        return self._create_and_start_language_server(ls_id)

    def remove_language_server(self, language: LanguageServerId, save_cache: bool = False) -> None:
        """
        Removes the language server for the given language, stopping it if it is running.

        :param language: the language
        """
        if language not in self._language_servers:
            raise ValueError(f"No language server for language {language.value} present; cannot remove")
        ls = self._language_servers.pop(language)
        self._stop_language_server(ls, save_cache=save_cache)

    def get_active_language_server_ids(self) -> list[LanguageServerId]:
        """
        Returns the list of languages for which language servers are currently managed.

        :return: list of languages

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Check ls_id in get_active_language_server_ids() before adding
  2. If replacement is intended, call remove_language_server(ls_id) first, then add_language_server
  3. Reuse the existing server via get_language_server for a representative file
  4. Wrap in try/except ValueError and treat 'already present' as success

Example fix

// before
manager.add_language_server(LanguageServerId.PYTHON)
# second call raises ValueError
manager.add_language_server(LanguageServerId.PYTHON)
// after
if LanguageServerId.PYTHON not in manager.get_active_language_server_ids():
    manager.add_language_server(LanguageServerId.PYTHON)
Defensive patterns

Strategy: validation

Validate before calling

if ls_id in manager.get_active_language_server_ids():
    manager.remove_language_server(ls_id)
manager.add_language_server(ls_id)

Try / catch

try:
    manager.add_language_server(ls_id)
except ValueError as e:
    if "already present" in str(e):
        pass  # treat as success
    else:
        raise

Prevention

When it happens

Trigger: Calling add_language_server(ls_id) twice; calling add for a language already started by from_languages; _ensure_functional_ls recovery logic racing with a user-initiated add.

Common situations: Startup code unconditionally adds servers after from_languages already created them; retry logic re-adding after a partial failure where the server actually started; plugin enabling a language that's already enabled.

Related errors


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