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_FILEThe 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.luaThis 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) btFor 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 errorFor 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.sockThen 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.c—MultiQueueoperations. A wedged queue is a common symptom.src/nvim/getchar.c#vgetcandsafe_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 RPCOr 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 withoutvim.schedule(). Wrap the callback. - Reentrancy panics. A function that triggers
os_breakcheck()was markedapi-fast. Either drop theapi-fastflag or refactor the callee to avoid the breakcheck. - TUI artifacts. First check whether the bug reproduces with
nvim --headlessdriven by a screenshot test. If yes, the bug is in the editor; if no, it is insrc/nvim/tui/. - Silent Lua errors in autocmds. Wrap the body in
pcallor check:messages. Errors innvim_create_autocmdcallbacks default to logging, not crashing. - Stale
.deps/. When a dependency is bumped incmake.deps/deps.txt, runmake distcleanbefore 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.