Error Handling in Neovim: pcall + vim.notify vs old try/catch

Why Error Handling Matters in Neovim

In a plugin-heavy config, things break. A missing dependency, a bad require, an API change — your Neovim should tell you clearly and gracefully, not crash with cryptic messages.

Vimscript’s try/catch was the only option for years. But with Neovim 0.12’s mature Lua API, pcall + vim.notify is the new standard.

Let’s compare them head-to-head with real, copy-paste-ready examples.

The Old Way: Vimscript try/catch

Still works, but verbose, limited, and hard to debug.

" In a .vim file or legacy plugin
try
  call luaeval('require("myplugin")')
  echo "Plugin loaded successfully"
catch
  echohl ErrorMsg
  echo "Plugin failed: " . v:exception
  echohl None
endtry
PROS
Works in pure Vimscript
CONS
No stack traces
Ugly echo output
Can’t easily log to file
Still used in very old plugins (pre-2020)

The Modern Way: Lua pcall + vim.notify

Clean, powerful, and integrated with Neovim’s notification system.

-- In init.lua or any Lua module
local ok, err = pcall(require, "myplugin")

if not ok then
  vim.notify(
    "Failed to load myplugin: " .. err,
    vim.log.levels.ERROR,
    { title = "Neovim Config" }
  )
  -- Optional: write to log
  vim.fn.writefile({err}, vim.fn.stdpath("log") .. "/config-errors.log", "a")
end
💡 Pro move: Use xpcall for full stack traces with a custom error handler.

Direct Comparison

Feature Vimscript try/catch Lua pcall + vim.notify
Readability Verbose & noisy Clean & concise
Error details v:exception only Full error + stack trace
User notification echohl + echo Beautiful floating popup (vim.notify)
Logging Manual only Easy file + levels
Async / callbacks Difficult Native with xpcall
2026 best practice Avoid Always use

Real-World Use Cases

Plugin loading in init.lua

local function safe_require(name)
  local ok, module = pcall(require, name)
  if not ok then
    vim.notify("Missing plugin: " .. name, vim.log.levels.WARN)
    return nil
  end
  return module
end

local telescope = safe_require("telescope")
if telescope then
  telescope.setup({})
end

Legacy Vimscript equivalent

try
  lua require("telescope")
catch
  echom "Missing plugin: telescope"
endtry

Tips