oraios/serena · error · RuntimeError

Failed to read nixd configuration file

Error message

Failed to read nixd configuration file '{config_path}': {exc}

What it means

This RuntimeError is raised when the nixd language-server configuration file referenced by the 'config_path' setting cannot be opened or read by the OS. The library reads the JSON config at startup (_load_nixd_settings) and wraps any OSError (missing file, permission denied, is-a-directory) into this error with the original OS message included. It is thrown from the nixd language server constructor, so server startup fails.

Solutions

  1. Verify the path in the nixd 'config_path' setting exists and is a regular readable file (ls -l <path>).
  2. Fix the path in settings to the correct absolute path of the nixd JSON config.
  3. Fix file permissions (chmod/chown) so the process user can read the file.
  4. If no custom config is needed, remove 'config_path' so built-in defaults are used.

Example fix

// before
config_path: "/home/user/.config/nixd/nixd.jscon"  // typo, file missing
// after
config_path: "/home/user/.config/nixd/nixd.json"
Defensive patterns

Strategy: validation

Validate before calling

import json, os

def validate_nixd_config_path(config_path: str) -> None:
    if not os.path.isabs(config_path):
        raise ValueError(f"config_path must be absolute: {config_path}")
    if not os.path.isfile(config_path):
        raise FileNotFoundError(f"nixd config not a readable file: {config_path}")
    if not os.access(config_path, os.R_OK):
        raise PermissionError(f"no read permission: {config_path}")
    with open(config_path, "r", encoding="utf-8") as f:
        json.load(f)  # also pre-checks JSON validity

Try / catch

try:
    server = NixdLanguageServer(config_path=cfg["nixd"]["config_path"], **common)
except RuntimeError as e:
    if "Failed to read nixd configuration file" in str(e):
        logger.error("Falling back to default nixd settings: %s", e)
        server = NixdLanguageServer(**common)  # omit config_path
    else:
        raise

Prevention

When it happens

Trigger: Calling the nixd language server __init__ with a 'config_path' setting pointing to a file that does not exist, has bad permissions, or is a directory; json.load then raises OSError (e.g. FileNotFoundError, PermissionError, IsADirectoryError) which is re-raised as RuntimeError.

Common situations: Typo in the config path in user settings; config file deleted or moved after settings were written; running the server as a different user without read permission; passing a directory path instead of a file path; relative path used while cwd differs from expectation (though validation usually requires absolute).

Related errors


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

Appendix: source

Thrown at src/solidlsp/language_servers/nixd_ls.py:263

        config_path_value = custom_settings.get("config_path")
        if config_path_value is None:
            return cls._create_default_nixd_settings()
        if not isinstance(config_path_value, str) or not config_path_value.strip():
            raise ValueError("ls_specific_settings.nix.config_path must be a non-empty absolute path")

        config_path = Path(config_path_value).expanduser()
        if not config_path.is_absolute():
            raise ValueError(f"ls_specific_settings.nix.config_path must be absolute: {config_path_value!r}")

        try:
            with config_path.open(encoding="utf-8") as config_file:
                settings = json.load(config_file)
        except json.JSONDecodeError as exc:
            raise ValueError(
                f"Invalid JSON in nixd configuration file '{config_path}': {exc.msg} (line {exc.lineno}, column {exc.colno})"
            ) from exc
        except OSError as exc:
            raise RuntimeError(f"Failed to read nixd configuration file '{config_path}': {exc}") from exc

        if not isinstance(settings, dict):
            raise ValueError(
                f"Invalid nixd configuration file '{config_path}': expected a JSON object containing the value of the 'nixd' section"
            )
        return settings

    @staticmethod
    def _resolve_nixd_configuration_section(settings: dict[str, Any], section: object) -> Any:
        """Resolve a ``nixd`` configuration section from the effective settings."""
        if section == "nixd":
            return deepcopy(settings)
        if not isinstance(section, str) or not section.startswith("nixd."):
            return {}

        value: Any = settings
        for key in section.removeprefix("nixd.").split("."):
            if not key or not isinstance(value, dict) or key not in value:

View on GitHub (pinned to 7fcbca7e62)