Overview & Root Cause Summary: The error
error: unable to unlink old '<filename>': Invalid argument(orPermission denied) occurs primarily on Windows during operations likegit checkout,git switch,git pull, orgit reset. In Windows, the operating system kernel enforces mandatory file locking—preventing files from being renamed or deleted if any active process (such as an IDE, language server, local development runner, or antivirus scanner) holds an open file handle to that path.
Understanding the Root Causes
- Active Open File Handles: Running dev servers (e.g., Node.js, Webpack, Vite, Python), debuggers, or text editors holding active locks on files Git attempts to replace or remove.
- Background Language Servers & Indexers: IDE extensions (such as TypeScript Server, OmniSharp, or ESLint daemon) indexing files in the background while Git modifies the working tree.
- Antivirus & Windows Defender Scans: Real-time endpoint security scanning newly created build artifacts or binaries, temporarily locking access during checkout operations.
- Read-Only File System Attributes: Build tools or previous operations setting the Windows
+r(read-only) attribute on tracked repository files.
Step 1: Quick Fix (Terminate Locking Processes & Retry)
Identify and terminate processes holding open handles to files in your repository, or close active IDE sessions before executing the checkout.
# 1. Stop all active development servers and background node runners (PowerShell):
Stop-Process -Name node, npm, python -Force -ErrorAction SilentlyContinue
# (On Linux / macOS):
killall -9 node python 2>/dev/null || true
# 2. Check for locking processes using Sysinternals Handle (if installed):
handle.exe <filename>
# 3. Retry the checkout or branch switch command:
git switch <target_branch>
Step 2: Remove Read-Only Attributes & Enable core.fscache
Ensure that Windows read-only flags are stripped from repository files and that Git’s internal file system caching optimization is active.
# 1. Remove read-only attributes recursively across your repository (PowerShell / Command Prompt):
attrib -r -s /s /d *.*
# 2. Enable Git's Windows filesystem cache for improved handle management:
git config --global core.fscache true
# 3. If the staging index was left in an inconsistent state, reset the index:
git reset HEAD
Step 3: Alternative Approach (Windows Defender Exclusions & Safe Reset)
Exclude your development directory from Windows Defender real-time scanning to permanently prevent scanner-induced file locking during fast branch switching.
# 1. Add your project root to Windows Defender exclusions (PowerShell as Administrator):
Add-MpPreference -ExclusionPath "C:\path\to\your\project"
# 2. If git checkout remains stuck on specific files, force a clean working tree reset:
git reset --hard HEAD
git clean -fd
# 3. Complete the branch switch:
git checkout <target_branch>
Verification & Testing Steps
Confirm that your working tree has cleanly transitioned to the target branch without residual locked files.
# 1. Verify active branch:
git branch --show-current
# 2. Confirm working tree status is clean:
git status
# 3. Test pulling or switching branches to verify locking resolution:
git pull origin $(git branch --show-current)
Summary Comparison Table
| Troubleshooting Approach | Target Locking Source | Data Loss Risk | Recommended Scenario |
|---|---|---|---|
| Terminate Active PIDs | Node/Python dev servers & watchers | None (Restarts servers) | First immediate response during active dev |
attrib -r Flag Removal |
Windows read-only file attributes | None | Permissions altered by build scripts |
core.fscache true |
Git Windows file handle caching | None | Standard optimization for all Windows Git users |
| Windows Defender Exclusion | Real-time filesystem scanning | None | Recurring checkout & rebase freezes on Windows |
Leave a Reply