[Fixed] error: unable to unlink old: Invalid argument in Git: Step-by-Step Troubleshooting Guide

Overview & Root Cause Summary: The error error: unable to unlink old '<filename>': Invalid argument (or Permission denied) occurs primarily on Windows during operations like git checkout, git switch, git pull, or git 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

Discover more from Victor's room

Subscribe now to keep reading and get access to the full archive.

Continue reading