From 5ad4795a764a89192e0082cb5056300855f14c03 Mon Sep 17 00:00:00 2001 From: Immanuel Haffner Date: Mon, 6 Jul 2026 13:00:00 +0000 Subject: [PATCH] fix(autocmds): guard debounced cursor action against wiped buffer The cursor autocmd (CursorMoved/CursorMovedI) defers its work through a debounce timer wrapped in vim.schedule_wrap, so the `action` closure runs on a later event-loop tick than the autocmd that queued it. The buffer id captured in `args.buf` is validated when the autocmd fires but not when the scheduled callback finally runs. If that buffer is wiped during the debounce window (e.g. a transient Telescope preview or scratch buffer), the captured id becomes dangling. The callback then reaches actions.render/clear -> renderer.clear -> markdown.clear -> nvim_buf_clear_namespace with a dead id, throwing: Invalid buffer id: N Re-validate `args.buf` at the top of the scheduled closure so it bails out cleanly when the buffer no longer exists. Behaviour is unchanged for live buffers; only the wiped-buffer race is short-circuited. --- lua/markview/autocmds.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lua/markview/autocmds.lua b/lua/markview/autocmds.lua index 757a9aa2..6cfe230b 100644 --- a/lua/markview/autocmds.lua +++ b/lua/markview/autocmds.lua @@ -352,6 +352,14 @@ autocmds.cursor = function (args) end local function action () + -- The debounce timer + vim.schedule_wrap mean this closure runs on a + -- later event-loop tick than the autocmd that queued it. The buffer + -- captured in `args.buf` may have been wiped in the meantime (e.g. a + -- transient Telescope preview or scratch buffer), leaving a dangling + -- id. Re-validate here, before any nvim_buf_* call reaches it. + if not args.buf or not vim.api.nvim_buf_is_valid(args.buf) then + return; + end require("markview.health").print({ from = "markview/autocmds.lua", fn = "cursor() -> action()",