Skip to main content

LSP Debugging

LSP issues are the most common source of frustration in a Neovim setup. This lesson provides a systematic debugging approach.

Step 1: Check Basic Health​

:checkhealth lsp

This shows:

  • Active clients
  • Any error messages from LSP initialization
  • Provider status (Node, Python, etc.)

Step 2: Verify LSP Attachment​

:LspInfo

Shows which servers are attached to the current buffer. If it says "No clients attached" — read on.

Step 3: Check Filetype Detection​

LSP servers attach based on filetype, not filename:

:set filetype? → shows current filetype

If it shows iletype= (empty) or the wrong type:

:set filetype=python → manually set it

Add an autocmd to fix it permanently:

vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, {
pattern = "*.env",
callback = function() vim.bo.filetype = "sh" end,
})

Step 4: Check Root Directory Detection​

Most LSPs require a project root directory (where they look for config files). If the root isn't detected, LSP won't start.

:lua print(vim.lsp.buf.list_workspace_folders())

Common root markers:

  • pyright: looks for pyproject.toml, setup.py, .git
  • s_ls: looks for package.json, sconfig.json
  • lua_ls: looks for .luarc.json, .git

Fix: Create the relevant config file in your project root, or initialize a git repo.

Step 5: Enable LSP Logging​

-- Enable debug-level LSP logs
vim.lsp.set_log_level("debug")

-- View logs
:lua vim.cmd("edit " .. vim.lsp.get_log_path())

This is verbose — disable after debugging:

vim.lsp.set_log_level("warn")

Step 6: Check Mason Installation​

:Mason → UI showing all installed servers
:MasonLog → installation logs

Verify the server binary is accessible:

# Check if server is in PATH after Mason installs
which lua-language-server
which pyright-langserver

Mason installs to ~/.local/share/nvim/mason/bin/. Add to PATH if needed:

~/.bashrc
export PATH="$HOME/.local/share/nvim/mason/bin:$PATH"

Common LSP Scenarios​

Intelephense Not Finding WordPress Functions​

  1. Ensure stubs = wordpress is in lspconfig settings
  2. Install WordPress stubs: composer require --dev php-stubs/wordpress-stubs
  3. Restart LSP: :LspRestart

ts_ls Too Many Errors for Old JS Codebase​

lspconfig.ts_ls.setup({
settings = {
typescript = { diagnostics = { ignoredCodes = { 7006, 7016 } } },
javascript = { diagnostics = { ignoredCodes = { 7006, 7016 } } },
},
})

Formatter Uses Wrong Server​

-- Specify which LSP handles formatting
vim.lsp.buf.format({
filter = function(client)
return client.name == "null-ls" -- only null-ls formats
end,
})

Restarting LSP​

:LspStop → stop all LSP clients
:LspStart → restart LSP for current filetype
:LspRestart → stop + start

In LazyVim​

LazyVim Context

LazyVim automatically configures LSP keymaps, attaches servers cleanly using vim-lspconfig, and manages formatters automatically via conform.nvim. The debugging steps remain similar, but LazyVim provides a helpful UI to see what LSPs are attached.

AspectVanilla NeovimLazyVim
LSP Info:LspInfo:LspInfo or <leader>cl (Lsp Info)
Mason Info:Mason:Mason or <leader>cm (Mason Info)
LSP Restart:LspRestartSame command works perfectly
Formatter InfoCustom null-ls check:ConformInfo (since LazyVim uses conform.nvim)

LazyVim Specific Debugging​

  • Check Formatter Status: Run :ConformInfo to see exactly which formatter is active for the current buffer, whether it's available, and if there are any errors.
  • LSP Linter Status: Run :lua print(vim.inspect(require('lint').linters_by_ft)) to see which linters are configured for the current filetype (if using vim-lint).
  • Disabling Format on Save: If an LSP or formatter is hanging and blocking your workflow, you can quickly toggle formatting on save using the &lt;leader&gt;uf keymap instead of modifying your configuration.

What's Next​