# Fix Vim Autocommand BufWritePre Infinite Loop Freezing Editor
You save a file in Vim and the editor freezes for several seconds. The error message eventually appears:
Error detected while processing BufWritePre Autocommands for "*":
E223: recursive autocommand: BufWritePre *Or Vim becomes completely unresponsive, consuming 100% CPU. The issue is an autocommand that triggers itself recursively, creating an infinite loop.
Understanding the Infinite Loop
The BufWritePre event fires just before Vim writes a buffer to disk. If your autocommand modifies the buffer (e.g., strips trailing whitespace, formats the file), the modification triggers BufWritePre again, which runs the autocommand again, creating an infinite loop.
A typical problematic autocommand:
" WRONG: This triggers BufWritePre when it saves
autocmd BufWritePre * :%s/\s\+$//eThe substitute command modifies the buffer, which triggers BufWritePre again.
Fixing the Loop: Disable Autocommands Temporarily
The standard pattern is to disable autocommands within the autocommand:
```vim autocmd BufWritePre * call StripTrailingWhitespace()
function! StripTrailingWhitespace() let l:save = winsaveview() autocmd! BufWritePre " Disable BufWritePre temporarily %s/\s\+$//e " Strip trailing whitespace autocmd BufWritePre * call StripTrailingWhitespace() " Re-enable call winrestview(l:save) endfunction ```
Or more elegantly, use eventignore:
```vim function! StripTrailingWhitespace() let l:save_cursor = getpos('.') set eventignore=BufWritePre %s/\s\+$//e set eventignore= call setpos('.', l:save_cursor) endfunction
autocmd BufWritePre * call StripTrailingWhitespace() ```
The eventignore setting tells Vim to ignore specified events during the function execution.
The nested Keyword
Sometimes you WANT an autocommand to trigger other autocommands. Use the nested keyword:
```vim " Without nested: second autocmd does NOT fire autocmd BufWritePre * normal gggqG
" With nested: second autocmd DOES fire autocmd BufWritePre * nested normal gggqG ```
The nested keyword allows the command to trigger other autocommands. Without it, Vim prevents nested autocommand execution to avoid infinite loops.
Debugging Autocommands
List all defined autocommands:
:autocmdFilter by event:
:autocmd BufWritePreThis shows every BufWritePre autocommand and where it was defined. Look for:
--- Autocommands ---
BufWritePre
* call StripTrailingWhitespace()
Last set from ~/.vimrc line 45
*.py execute "!black " . expand("%")
Last set from ~/.vimrc line 52If you see multiple BufWritePre autocommands, they may be interfering with each other.
Verbose Autocommand Tracing
To trace exactly which autocommands fire:
:set verbose=9
:wWith verbose=9, Vim logs every autocommand execution. The output is voluminous but reveals the exact chain of events:
Executing BufWritePre Auto commands for "*"
autocommand call StripTrailingWhitespace()
Executing BufWritePre Auto commands for "*"
autocommand call StripTrailingWhitespace()
... (repeats)If you see the same autocommand executing multiple times during a single save, you have a recursive loop.
Common Problematic Autocommands
Auto-formatting on Save
```vim " WRONG: May trigger BufWritePre if format writes the buffer autocmd BufWritePre * :normal gggqG
" CORRECT: Use eventignore function! AutoFormat() set eventignore=BufWritePre normal gggqG set eventignore= endfunction autocmd BufWritePre * call AutoFormat() ```
Running External Commands
```vim " WRONG: External command output may modify buffer autocmd BufWritePre *.py execute "!python -m pyflakes " . expand("%")
" CORRECT: Use BufWritePost instead (runs AFTER save) autocmd BufWritePost *.py execute "!python -m pyflakes " . expand("%") ```
Use BufWritePost for commands that should run after the file is saved.
Auto-removing Trailing Whitespace (Fixed Version)
```vim function! TrimWhitespace() let l:view = winsaveview() keepjumps %s/\s\+$//e call winrestview(l:view) endfunction
augroup trim_whitespace autocmd! autocmd BufWritePre * call TrimWhitespace() augroup END ```
The keepjumps prevents the substitute from adding an entry to the jump list, and the augroup with autocmd! ensures the autocommand is only defined once (preventing multiple registrations that could cause issues).
Preventing Duplicate Autocommands
Always use augroups to prevent duplicate autocommand registration:
```vim " WRONG: Each time .vimrc is sourced, another autocmd is added autocmd BufWritePre * call TrimWhitespace()
" CORRECT: augroup clears previous definitions augroup my_autocmds autocmd! autocmd BufWritePre * call TrimWhitespace() augroup END ```
The autocmd! inside the augroup removes all previous autocommands in that group before defining new ones. This prevents accumulation when you source your .vimrc multiple times.