From 543a96e49179060999ebcb12372ce36ea6be646d Mon Sep 17 00:00:00 2001 From: "Kim A. Brandt" Date: Sun, 12 Jul 2026 18:52:10 +0200 Subject: [PATCH] fix(lsp): unclear error on malformed server responses #40422 Problem: Malformed server responses with `null` (vim.NIL) values, do not show clear error messages. Solution: Assert two known, specific cases, to avoid user confusion. --- runtime/lua/vim/diagnostic/_float.lua | 1 + runtime/lua/vim/lsp/diagnostic.lua | 1 + test/functional/lua/diagnostic_spec.lua | 16 ++++++++++++++++ test/functional/plugin/lsp/diagnostic_spec.lua | 16 ++++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/runtime/lua/vim/diagnostic/_float.lua b/runtime/lua/vim/diagnostic/_float.lua index 4cda1be61f..aa41cdd38e 100644 --- a/runtime/lua/vim/diagnostic/_float.lua +++ b/runtime/lua/vim/diagnostic/_float.lua @@ -211,6 +211,7 @@ function M.open(opts, ...) --- @type lsp.DiagnosticRelatedInformation[] local related_info = vim.tbl_get(diagnostic, 'user_data', 'lsp', 'relatedInformation') or {} + assert(related_info ~= vim.NIL, 'server response has invalid (null) relatedInformation') -- Below the diagnostic, show its LSP related information (if any) in the form of file name and -- range, plus description. for _, info in ipairs(related_info) do diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 9c07b05165..c4f18a0786 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -83,6 +83,7 @@ end --- @return table? local function tags_lsp_to_vim(diagnostic, client_id) local tags ---@type table? + assert(diagnostic.tags ~= vim.NIL, 'server response has invalid (null) tags') for _, tag in ipairs(diagnostic.tags or {}) do if tag == protocol.DiagnosticTag.Unnecessary then tags = tags or {} diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 782f0aa603..5b7bb4f372 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -3657,6 +3657,22 @@ describe('vim.diagnostic', function() ) end) + it('errors when LSP relatedInformation is null', function() + matches( + 'server response has invalid %(null%) relatedInformation', + pcall_err( + exec_lua, + [[ + local diagnostic = _G.make_warning('Some warning', 1, 1, 1, 3) + diagnostic.user_data = { lsp = { relatedInformation = vim.NIL } } + vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr) + vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, { diagnostic }) + vim.diagnostic.open_float({ header = false, scope = 'buffer' }) + ]] + ) + ) + end) + it('works with the old signature', function() eq( { '1. Syntax error' }, diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 1edc4a7e2b..176be2dfad 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -7,6 +7,8 @@ local clear = n.clear local exec_lua = n.exec_lua local eq = t.eq local neq = t.neq +local matches = t.matches +local pcall_err = t.pcall_err local create_server_definition = t_lsp.create_server_definition @@ -300,6 +302,20 @@ describe('vim.lsp.diagnostic', function() end) ) end) + + it('errors when diagnostic tags is null', function() + matches( + 'server response has invalid %(null%) tags', + pcall_err(exec_lua, function() + vim.lsp.diagnostic.on_publish_diagnostics(nil, { + uri = fake_uri, + diagnostics = { + vim.tbl_extend('force', _G.make_error('Diagnostic', 0, 0, 0, 0), { tags = vim.NIL }), + }, + }, { client_id = client_id }) + end) + ) + end) end) describe('vim.lsp.diagnostic.on_diagnostic', function()