Open-Source Wikis

/

Neovim

/

How to contribute

/

Debugging

neovim/neovim

Debugging

Bugs in Neovim usually fall into one of: a logic bug in C, a Lua exception, a C-level memory error, or a deadlock between the libuv loop and the input layer. The right tool is different in each case.

Step zero: the log

Neovim writes a single log file, location chosen by $NVIM_LOG_FILE or stdpath('log') .. '/log'. From inside Neovim:

:edit $NVIM_LOG_FILE

The log.c module respects vim.lsp.log.set_level(...) and the NVIM_LOG_LEVEL env var. Set it to DEBUG for the noisy version. Sources are tagged so you can grep for LSP, RPC, tui, etc.

Reproduce with --clean

Always reproduce against nvim --clean. If the bug needs a config or plugin, distill it into the smallest repro using contrib/minimal.lua:

nvim --clean -u contrib/minimal.lua

This is the standard expected attachment for bug reports.

C-level crashes

For a segfault or assertion failure:

make CMAKE_BUILD_TYPE=Debug
gdb --args ./build/bin/nvim --clean
# (gdb) run
# ... reproduce ...
# (gdb) bt

For a more useful backtrace, build with sanitizers:

rm -rf build
CMAKE_EXTRA_FLAGS="-DCMAKE_C_COMPILER=clang -DENABLE_ASAN_UBSAN=1" make
ASAN_OPTIONS=log_path=/tmp/nvim_asan ./build/bin/nvim ...

If Neovim aborts unexpectedly, check /tmp/nvim_asan.<pid> for ASAN's report. UBSAN reports go to the same file. The detailed instructions, including a recommended UBSAN suppressions list, are in CONTRIBUTING.md under "Sanitizers (ASAN and UBSAN)".

For undefined behavior that ASAN doesn't catch, valgrind is still useful for :terminal and vim.system PTY paths:

VALGRIND=1 ./build/bin/nvim ...

Lua errors

The editor catches Lua errors and surfaces them as :messages and in the log. To break execution at a Lua error:

:luafile-on-error
" or just call vim.print() before the error

For interactive debugging:

-- Drop a print statement
vim.print(some_value)

-- Set a luaprint or use vim.api.nvim_err_writeln
vim.api.nvim_err_writeln(vim.inspect(some_value))

For a real REPL on the running editor:

nvim --headless --listen /tmp/nvim.sock
nvim --remote-ui --server /tmp/nvim.sock

Then attach a Lua REPL via nvim_exec_lua over RPC.

Tracing the event loop

When a bug looks like "Neovim hangs", the most likely culprit is the event loop. Useful entry points:

  • src/nvim/event/loop.c#loop_poll_events — top of the libuv loop.
  • src/nvim/event/multiqueue.cMultiQueue operations. A wedged queue is a common symptom.
  • src/nvim/getchar.c#vgetc and safe_vgetc — where the input loop drives event processing.

Adding a DLOG("foo") call (src/nvim/log.h) is the quick way to instrument these without a debugger.

RPC traffic

To see what a UI is sending or receiving:

NVIM_LOG_FILE=/tmp/nvim.log NVIM_LOG_LEVEL=DEBUG nvim
tail -F /tmp/nvim.log | grep RPC

Or attach with a log-capturing client; pynvim has built-in tracing under NVIM_PYTHON_LOG_LEVEL=DEBUG.

Coverity

Coverity runs against master continuously. Defect reports require requesting access at https://scan.coverity.com/projects/neovim-neovim. When fixing a Coverity defect, the commit message should be:

fix(coverity/{id}): {description}

git log --grep coverity --oneline shows existing examples.

Common pitfalls

  • Assertion in is_main_thread(). You called an editor function from the libuv thread without vim.schedule(). Wrap the callback.
  • Reentrancy panics. A function that triggers os_breakcheck() was marked api-fast. Either drop the api-fast flag or refactor the callee to avoid the breakcheck.
  • TUI artifacts. First check whether the bug reproduces with nvim --headless driven by a screenshot test. If yes, the bug is in the editor; if no, it is in src/nvim/tui/.
  • Silent Lua errors in autocmds. Wrap the body in pcall or check :messages. Errors in nvim_create_autocmd callbacks default to logging, not crashing.
  • Stale .deps/. When a dependency is bumped in cmake.deps/deps.txt, run make distclean before rebuilding. The CMake fetch caches by URL, not hash.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Debugging – Neovim wiki | Factory