Skip to content
Fran Gonzalez
← Back to blog
(updated Jun 27, 2026)·Clanker·3 min read

mise shims resolve from cwd, not buffer path

mise shims on PATH is the documented approach for Neovim IDE integration, but LSP servers started from the wrong cwd resolve the wrong tool version.

Some matmuls wrote this slop, sorry. My goal with this content is to document some work I (a real human bean) do while poking the Clanker, and try to learn something along the way.

jdtls was crashing with exit code 1 when I opened a Java file via fuzzy finder: the mise shim resolved Java from nvim’s startup directory instead of the project’s mise.toml.

What I Learned

The mise IDE integration docs recommend prepending shims to PATH for Neovim:

-- init.lua
vim.env.PATH = vim.env.HOME .. "/.local/share/mise/shims:" .. vim.env.PATH

This benefits all tools (Node, Python, Java, etc.), and I added it. But shims resolve tool versions based on the process’s cwd, not the buffer’s file path. When I launch nvim from ~ and use <leader>fp to open a file in a project directory, nvim’s cwd stays at ~. The fuzzy finder opens the file without calling :cd.

LSP servers spawned by nvim inherit this cwd. The Mason jdtls wrapper calls java -version to validate the JDK. The shim at ~/.local/share/mise/shims/java resolves from ~, finds no mise.toml with a Java version, and falls through to the system /usr/bin/java, which is broken on this machine.

The fix is a hybrid. The shims PATH stays (it is the mise-documented baseline and benefits all tools). For LSP servers specifically, I resolve the tool path from the project root inside the root_dir(bufnr, on_dir) callback, before the server process spawns:

-- Resolve JAVA_HOME from the project root via mise.
-- root_dir resolves from the buffer's file path, not nvim's cwd.
local function set_java_home(dir)
  if vim.fn.executable("mise") ~= 1 then
    return
  end
  local result = vim.fn.systemlist("cd " .. vim.fn.shellescape(dir) .. " && mise where java 2>/dev/null")
  if result and result[1] and result[1] ~= "" then
    vim.env.JAVA_HOME = result[1]:gsub("[\n\r]", "")
  end
end

I call set_java_home(root) before on_dir(root), so JAVA_HOME is set before the jdtls process spawns. The Mason wrapper finds JAVA_HOME and uses $JAVA_HOME/bin/java. This works regardless of where nvim was launched, because root_dir resolves from the buffer’s file path.

The mise docs mention mise where as a way to find tool paths programmatically. Combining shims PATH (for general tool resolution) with per-project mise where calls inside LSP callbacks (for cwd-independent resolution) covers both cases.

The full jdtls config, including the root_dir gate that scopes jdtls to the Maven backend, is in Scoping nvim-jdtls to a Maven subproject in a polyglot LazyVim setup.

References

  • mise IDE Integration. The official Neovim recommendation: prepend shims to PATH. Also documents the limitation: “Once you have launched the IDE, it won’t reload the environment variables or the PATH.”
  • vim.lsp.enable(). Documents the root_dir(bufnr, on_dir) callback signature used to set JAVA_HOME before the server spawns.
  • mise where. CLI command to resolve a tool’s install path for the current directory.

This post was written with AI assistance.