Skip to content

vale sync fails on startup with OS error 2 when LSP client does not send rootUri #30

@veshivas

Description

@veshivas

Summary

When syncOnStartup is enabled but the LSP client does not send rootUri in the initialize request, vale sync fails with OS error 2 (ENOENT) without ever invoking the vale binary.

Root cause

do_sync passes root_path() as the working directory to cli.sync(). root_path() is populated from rootUri in the LSP initialize request. When the client does not send rootUri (common in IDE-embedded LS clients such as Qt Creator's Vale extension), cwd remains an empty string. Passing "" to Command::current_dir causes the OS to reject the process spawn with ENOENT before vale is ever executed.

// server.rs
async fn do_sync(&self) {
    match self.cli.sync(self.config_path(), self.root_path()) { // root_path() may be ""
// vale.rs
pub(crate) fn sync(&self, config_path: String, cwd: String) -> Result<(), Error> {
    ...
    let _ = Command::new(exe.as_os_str())
        .current_dir(cwd.clone()) // "" → OS error 2 before vale is spawned

Why linting still works

run() always sets cwd = fp.parent() — the parent directory of the file being linted — so it never relies on root_path() and is unaffected.

Why cwd doesn't matter for sync

vale sync only downloads packages listed in the config. When configPath is an absolute path, vale does not use cwd to locate the config or StylesPath. Any valid directory works — cwd is only needed to satisfy the OS process spawn requirement.

Fix

Fall back to env::current_dir() in sync() when cwd is empty:

let resolved_cwd = if cwd.is_empty() {
    env::current_dir().unwrap_or_else(|_| PathBuf::from("/"))
} else {
    PathBuf::from(&cwd)
};

let exe = self.exe_path(false)?;
let _ = Command::new(exe.as_os_str())
    .current_dir(resolved_cwd)
    .args(args)
    .output()?;

Steps to reproduce

  1. Configure vale-ls with syncOnStartup: true and an absolute configPath.
  2. Use an LSP client that does not send rootUri on initialize (e.g. Qt Creator's Vale LS extension).
  3. Start vale-ls — it reports "Failed to sync CLI: OS error 2".
  4. Run vale sync manually in a terminal → succeeds.
  5. Reopen the file — linting works normally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions