Windows: Real nul files from older versions require \\?\ path for detection and cleanup
Windows: Real nul files from older versions require \\\\?\\ path for detection and cleanup
Environment
- Claude Code version at time of contamination: 2.1.39 (or earlier)
- Claude Code version tested: 2.1.69 (fix confirmed working — no new nul files created)
- OS: Windows 11 Home 10.0.26200
- Filesystem: C: (NTFS), D: (ReFS Dev Drive), H: (NTFS)
- Shell: Git Bash (Claude Code's Bash tool)
Related Issues
- #4928 - [BUG] file named nul created on windows (closed, locked)
- #17783 - Windows: Temp directories and nul files not cleaned up (closed, locked)
- #17925 - Temporary files not cleaned up on Windows (closed, locked)
TL;DR
Claude Code versions before ~2.1.42 created real nul files on Windows via Git Bash's > nul redirection. The fix is confirmed working in 2.1.69. However:
- Orphaned real nul files persist from older versions and cause sync/backup tool failures
- The obvious cleanup method doesn't work —
Remove-Itemanddelsilently no-op against files namednulbecause Windows resolves the name to the NUL device - The obvious detection method is wildly misleading —
Get-ChildItem -Filter 'nul'returns phantom device node entries in every directory on the system, inflating counts by orders of magnitude - Correct cleanup requires the
\\?\path prefix to bypass Windows device name resolution
The detection pitfall
On Windows, NUL is a reserved device name (like COM1, LPT1). When PowerShell's Get-ChildItem -Filter 'nul' enumerates a directory, it reports a phantom entry for the NUL device — even in brand-new empty directories:
# Phantom nul appears in a directory that was just created empty
$dir = "C:\test_phantom"
New-Item -ItemType Directory -Path $dir -Force | Out-Null
(Get-ChildItem -Path $dir -Filter 'nul' -File).FullName # Returns "C:\test_phantom\nul"
Remove-Item $dir -Force
A naive recursive scan reports one nul "file" per directory on the system. On my machine: 133,646 phantom entries across three drives (C:, D:, H:). These are not real files — they can't be read, can't be deleted, and appear identically in directories Claude Code has never touched.
How to find REAL nul files
The \\?\ path prefix tells Windows to treat nul as a literal filename, bypassing device name resolution. Only real files show up:
# Correct detection: only finds real nul files, not phantom device nodes
Get-ChildItem -Path "D:\" -Recurse -Filter 'nul' -File -ErrorAction SilentlyContinue |
Where-Object {
try {
$found = [System.IO.Directory]::GetFiles("\\?\$($_.DirectoryName)", "nul")
$found.Count -gt 0
} catch { $false }
} |
ForEach-Object { Write-Host $_.FullName }
On my system this found 4 real nul files (vs 133,646 phantom entries):
C:\Users\[USER]\.claude\nul
D:\dev\nul
D:\dev\projects\[PROJECT]\nul
H:\Data\raw-data\[PROJECT]\nul
Every one was in a directory Claude Code had used as a working directory.
How to delete real nul files
Standard deletion methods silently fail because Windows resolves nul to the NUL device:
# These all silently "succeed" but don't actually delete anything:
Remove-Item "path\nul" -Force # No-op
Remove-Item -LiteralPath "\\?\path\nul" -Force # No-op (Remove-Item still resolves)
cmd /c 'del /f "path\nul"' # "syntax is incorrect"
[System.IO.File]::Delete("path\nul") # Tries \\.\nul, access denied
The only method that works:
# Delete via \\?\ prefix using .NET — bypasses device name resolution
[System.IO.File]::Delete("\\?\C:\Users\[USER]\.claude\nul")
Complete cleanup script
# Save as cleanup_real_nul.ps1 and run with:
# powershell -ExecutionPolicy Bypass -File cleanup_real_nul.ps1
$drives = @("C:\", "D:\", "H:\") # Adjust to your drives
$deleted = 0
$phantoms = 0
foreach ($drive in $drives) {
Write-Host "Scanning $drive ..." -ForegroundColor Cyan
Get-ChildItem -Path $drive -Recurse -Filter 'nul' -File -ErrorAction SilentlyContinue |
ForEach-Object {
$longDir = "\\?\$($_.DirectoryName)"
try {
$found = [System.IO.Directory]::GetFiles($longDir, "nul")
if ($found.Count -gt 0) {
$longPath = "\\?\$($_.FullName)"
[System.IO.File]::Delete($longPath)
# Verify
$still = [System.IO.Directory]::GetFiles($longDir, "nul")
if ($still.Count -eq 0) {
Write-Host " DELETED: $($_.FullName)" -ForegroundColor Green
$deleted++
} else {
Write-Host " FAILED: $($_.FullName)" -ForegroundColor Red
}
} else {
$phantoms++
}
} catch {
$phantoms++
}
}
}
Write-Host ""
Write-Host "Real nul files deleted: $deleted" -ForegroundColor Green
Write-Host "Phantom device nodes skipped: $phantoms" -ForegroundColor Gray
Why this matters
Real nul files cause problems for file sync and backup tools:
- Tresorit: Flags
nulas an invalid filename that can't sync - FreeFileSync: Requires explicit exclusion filters for
nul(never needed before Claude Code) - iDrive: High CPU usage and errors when encountering
nulfiles (also reported by @trueliarx on #17783)
These tools use Win32 FindFirstFile which correctly distinguishes real files from device nodes — so they only flag the real Claude-created files, not the phantoms. But users investigating the problem with PowerShell will see 100K+ phantom entries and assume the problem is far worse than it is.
Fix verification
Tested on version 2.1.69: deleted all 4 real nul files, ran a full session with multiple Bash tool invocations (git status, python --version, ls), re-scanned — zero new real nul files created. The fix in ~2.1.42 is working.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗