diff --git a/runtime/lua/nvim/autoread.lua b/runtime/lua/nvim/autoread.lua index 2691e8ccc2..5016c43f03 100644 --- a/runtime/lua/nvim/autoread.lua +++ b/runtime/lua/nvim/autoread.lua @@ -140,13 +140,19 @@ local function ensure_watcher(bufnr) set_pending(bufnr, false) return end - vim.cmd.checktime(bufnr) + -- Use pcall: autocmds (e.g. ftplugin) may throw during reload for any reason. + local ok, err = pcall(vim.cmd.checktime, bufnr) ---@type any, any set_pending(bufnr, false) -- On rename events (e.g. atomic save by another editor), the watcher -- is now stale (watching the old inode). Re-establish it. if change_type ~= watch.FileChangeType.Changed then ensure_watcher(bufnr) end + if not ok then + vim.api.nvim_echo({ + { ('autoread: :checktime failed for buffer %d: %s'):format(bufnr, err) }, + }, true, { err = true }) + end end) end) end) diff --git a/test/functional/options/autoread_spec.lua b/test/functional/options/autoread_spec.lua index ad9bc13d2c..d3c7ab2052 100644 --- a/test/functional/options/autoread_spec.lua +++ b/test/functional/options/autoread_spec.lua @@ -199,6 +199,26 @@ describe('autoread file watcher', function() end) end) + it('handles autocmd error during reload', function() + local path = open_watched('original\n') + local bufnr = api.nvim_get_current_buf() + + -- Define a broken autocmd. + n.exec_lua([[ + vim.api.nvim_create_autocmd('FileChangedShellPost', { + callback = function() error('boom from test autocmd') end, + }) + ]]) + + write_file(path, 'changed\n') + + -- autoread should surface the error, and do its cleanup despite the failed autocmd. + retry(nil, 3000, function() + t.matches('autoread:.*boom from test autocmd', n.eval('v:errmsg')) + eq(0, api.nvim_get_option_value('busy', { buf = bufnr })) + end) + end) + it('detects changes after atomic rename (external editor save)', function() local path = open_watched('original\n')