oraios/serena · error · ValueError

No language server for language {language.value} present; ca

Error message

No language server for language {language.value} present; cannot remove

What it means

remove_language_server only removes languages currently tracked in _language_servers and raises ValueError for absent ones. After removal the server is stopped (optionally saving its cache). This error indicates the manager state doesn't match the caller's expectation.

Source

Thrown at src/serena/ls_manager.py:221

    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
        """
        return list(self._language_servers.keys())

    @staticmethod
    def _stop_language_server(ls: SolidLanguageServer, save_cache: bool = False, timeout: float = 2.0) -> None:
        if ls.is_running():
            if save_cache:
                ls.save_cache()
            log.info(f"Stopping language server for language {ls.ls_id} ...")
            ls.stop(shutdown_timeout=timeout)

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Check language in get_active_language_server_ids() before removing
  2. Make cleanup idempotent: catch ValueError and continue
  3. Track which languages were successfully added before tearing down

Example fix

// before
for lang in configured_languages:
    manager.remove_language_server(lang)  # raises if absent
// after
for lang in manager.get_active_language_server_ids():
    manager.remove_language_server(lang)
Defensive patterns

Strategy: validation

Validate before calling

active = manager.get_active_language_server_ids()
for lang in active:
    manager.remove_language_server(lang)

Try / catch

try:
    manager.remove_language_server(language)
except ValueError as e:
    if "cannot remove" in str(e):
        pass  # already gone; cleanup is idempotent
    else:
        raise

Prevention

When it happens

Trigger: Calling remove_language_server for a language never added, already removed, or never started because from_languages failed for it.

Common situations: Teardown code unconditionally removing all configured languages; double cleanup after an exception path already stopped servers; removing a language whose startup failed in from_languages (manager never created).

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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