helix-editor/helix · error · StartupError

Language server '{name}' not defined

Error message

Language server '{name}' not defined

What it means

During language-server startup, Registry::start_client looks up the requested server name in the syntax loader's language_server_configs (the [language-server.<name>] tables merged from languages.toml and user config). If no table with that exact name exists, this error is returned and the server never starts.

Source

Thrown at helix-lsp/src/lib.rs:632

        instances.retain(|ls| id != ls.id());
        if instances.is_empty() {
            self.inner_by_name.remove(client.name());
        }
    }

    fn start_client(
        &mut self,
        name: String,
        ls_config: &LanguageConfiguration,
        doc_path: Option<&std::path::Path>,
        root_dirs: &[PathBuf],
        enable_snippets: bool,
    ) -> Result<Arc<Client>, StartupError> {
        let syn_loader = self.syn_loader.load();
        let config = syn_loader
            .language_server_configs()
            .get(&name)
            .ok_or_else(|| anyhow::anyhow!("Language server '{name}' not defined"))?;
        let id = self.inner.try_insert_with_key(|id| {
            start_client(
                id,
                name,
                ls_config,
                config,
                doc_path,
                root_dirs,
                enable_snippets,
            )
            .map(|client| {
                self.incoming.push(UnboundedReceiverStream::new(client.1));
                client.0
            })
        })?;
        Ok(self.inner[id].clone())
    }

View on GitHub (pinned to 079a789e8c)

Solutions

  1. Check 'hx --health <lang>' - it shows which language servers are configured/available and surfaces this mismatch
  2. Add the missing definition block: [language-server.foo] with command = "..." in languages.toml (user or workspace), or fix the name to match an existing block exactly (case-sensitive)
  3. If you overrode the language's table in user config, re-add the [language-server.<name>] blocks the default languages.toml shipped for it

Example fix

# before - reference without definition
[language-server.myls]
# (missing)
[[language]]
name = "mylang"
language-server = [{ name = "myls" }]

# after
[language-server.myls]
command = "mylang-server"
args = ["--stdio"]

[[language]]
name = "mylang"
language-server = [{ name = "myls" }]
Defensive patterns

Strategy: validation

Validate before calling

// Validate language-server references against definitions before startup:
fn ls_refs_defined(lang: &LanguageConfiguration, defs: &HashSet<String>) -> Result<(), String> {
    for ls in &lang.language_server {
        if !defs.contains(&ls.name) {
            return Err(format!("language server '{}' not defined", ls.name));
        }
    }
    Ok(())
}

Type guard

fn is_defined_ls(name: &str, syn_loader: &helix_core::syntax::Loader) -> bool {
    syn_loader.language_server_configs().contains_key(name)
}

Prevention

When it happens

Trigger: A language's language-server = [{ name = "foo" }] (or the legacy language-server = ["foo"] list) references a name that has no [language-server.foo] section anywhere - typo, wrong case, or a server defined only in another config layer that got shadowed/removed by user languages.toml merging.

Common situations: User adds a language override in ~/.config/helix/languages.toml that replaces the default language table (array of tables semantics) and forgets to carry over the [language-server.x] definition; renaming a server block but not its reference; disabling a built-in definition while still referencing it; name casing ('vscode-html-language-server' vs 'vscode-html-language-server-removed').

Related errors


AI-assisted analysis of helix-editor/helix@079a789e8c (2026-08-16). Data as JSON: /api/errors/01a111603538da47. Report an issue: GitHub.