oraios/serena · error · RuntimeError

Could not find sourcekit-lsp, please install it as…

Error message

Could not find sourcekit-lsp, please install it as described in https://github.com/apple/sourcekit-lsp#installationAnd make sure it is available on your PATH.

What it means

The wrapper RuntimeError from _get_sourcekit_lsp_version's except clause: any failure to probe sourcekit-lsp (missing binary, non-zero exit) is normalized to this install-guidance message, chained from the original exception. It indicates the Swift toolchain LSP server is unavailable, so the SourceKit language server cannot start.

Solutions

  1. Install the Swift toolchain from swift.org (includes sourcekit-lsp) or full Xcode on macOS.
  2. Ensure the binary resolves: `which sourcekit-lsp`; add the toolchain usr/bin to PATH if not.
  3. Inspect the chained cause (`raise ... from e`) message to distinguish not-found vs non-zero exit.
  4. On Linux CI, use the official swift Docker image which bundles sourcekit-lsp.

Example fix

// before: CI image without swift
FROM ubuntu:22.04
// after
FROM swift:5.10-jammy
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil
assert shutil.which("sourcekit-lsp"), "sourcekit-lsp missing from PATH; install Swift toolchain first"

Type guard

def has_sourcekit_lsp() -> bool:
    import shutil
    return shutil.which("sourcekit-lsp") is not None

Try / catch

try:
    server = SourceKitLSP(config, repo_root, settings)
except RuntimeError as e:
    if "Could not find sourcekit-lsp" in str(e):
        print(e.__cause__)  # distinguish not-found vs non-zero exit
        raise SystemExit("Install sourcekit-lsp: https://github.com/apple/sourcekit-lsp#installation") from e
    raise

Prevention

When it happens

Trigger: Initializing SourceKitLSP when the `sourcekit-lsp` executable is absent from PATH or `sourcekit-lsp -h` exits non-zero; the chained `from e` exception holds the underlying cause.

Common situations: Fresh machines without Swift tooling, Docker images lacking swift runtime, minimal Xcode CLT-only installs where sourcekit-lsp ships only with full Xcode, CI runners with restricted PATH.

Related errors


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

Appendix: source

Thrown at src/solidlsp/language_servers/sourcekit_lsp.py:43

    def is_ignored_dirname(self, dirname: str) -> bool:
        # For Swift projects, we should ignore:
        # - .build: Swift Package Manager build artifacts
        # - .swiftpm: Swift Package Manager metadata
        # - node_modules: if the project has JavaScript components
        # - dist/build: common output directories
        return super().is_ignored_dirname(dirname) or dirname in [".build", ".swiftpm", "node_modules", "dist", "build"]

    @staticmethod
    def _get_sourcekit_lsp_version() -> str:
        """Get the installed sourcekit-lsp version or raise error if sourcekit was not found."""
        try:
            result = subprocess_run(["sourcekit-lsp", "-h"], capture_output=True, text=True, check=False)
            if result.returncode == 0:
                return result.stdout.strip()
            else:
                raise Exception(f"`sourcekit-lsp -h` resulted in: {result}")
        except Exception as e:
            raise RuntimeError(
                "Could not find sourcekit-lsp, please install it as described in https://github.com/apple/sourcekit-lsp#installation"
                "And make sure it is available on your PATH."
            ) from e

    def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings):
        sourcekit_version = self._get_sourcekit_lsp_version()
        log.info(f"Starting sourcekit lsp with version: {sourcekit_version}")

        super().__init__(
            config, repository_root_path, ProcessLaunchInfo(cmd="sourcekit-lsp", cwd=repository_root_path), "swift", solidlsp_settings
        )
        self.request_id = 0
        self._did_sleep_before_requesting_references = False
        self._initialization_timestamp: float | None = None

    @override
    def _document_symbols_cache_fingerprint(self) -> Hashable:
        normalize_symbol_name_version = 1

View on GitHub (pinned to 7fcbca7e62)