claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] file named nul created on windows

Open rweijnen opened this issue 5 months ago • 90 comments

Environment

  • Platform (select one):
  • [ ] Anthropic API
  • [x] Other: Claude CLI
  • Claude CLI version: 1.0.62
  • Operating System: Windows
  • Terminal:

Bug Description

Claude CLI is creating an unwanted file named "nul" in the current directory during execution. This appears to be related to incorrect handling of null device redirection on Windows systems.

Steps to Reproduce

  1. Run Claude CLI commands on Windows with version 1.0.62
  2. Check the current working directory after command execution
  3. Observe that a file named "nul" has been created

Expected Behavior

No "nul" file should be created. Output redirection to null device should properly use Windows equivalent (>nul or 2>nul) without creating actual files.

Actual Behavior

A file named "nul" is created in the current directory, suggesting the CLI is attempting to redirect output using Unix-style /dev/null syntax which Windows interprets as a literal filename.

Additional Context

This issue is likely caused by cross-platform compatibility problems where Unix-style null device redirection (>/dev/null) is being used instead of Windows-appropriate syntax (>nul). The behavior appears intermittent ("sometimes created"), which may depend on specific command paths or error handling routines within the CLI.

rweijnen avatar Aug 01 '25 14:08 rweijnen

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/4206
  2. https://github.com/anthropics/claude-code/issues/3839
  3. https://github.com/anthropics/claude-code/issues/4535

If your issue is a duplicate, please close it and šŸ‘ the existing issue instead.

šŸ¤– Generated with Claude Code

github-actions[bot] avatar Aug 01 '25 14:08 github-actions[bot]

I'm still experiencing this on version 1.0.72

phoenixtail26 avatar Aug 09 '25 15:08 phoenixtail26

You can delete by prepending \?\ to the full path eg \?\c:\myfolder\nul On Sat, 9 Aug 2025 at 20:50, Robert McLaws @.***> wrote:

robertmclaws left a comment (anthropics/claude-code#4928) https://github.com/anthropics/claude-code/issues/4928#issuecomment-3172030845

Also, I can't delete the file in Windows which is really annoying.

— Reply to this email directly, view it on GitHub https://github.com/anthropics/claude-code/issues/4928#issuecomment-3172030845, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABZZRQY4I4FERLU65YXRAUD3MY7GNAVCNFSM6AAAAACC445NFGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTCNZSGAZTAOBUGU . You are receiving this because you authored the thread.Message ID: @.***>

rweijnen avatar Aug 09 '25 21:08 rweijnen

The way I've been deleting them is to add them in 7zip and have it delete the file after compressing. Really dumb, but the nul file borks my Git commits otherwise.

Boh1 avatar Aug 19 '25 02:08 Boh1

Confirmed same issue

craigvc avatar Aug 19 '25 16:08 craigvc

I'm having the same issue.

RadicalCaitlin avatar Aug 25 '25 12:08 RadicalCaitlin

Confirmed issue in the version: 1.0.90

JhonHawk avatar Aug 27 '25 09:08 JhonHawk

Just happened, claude code v1.0.95

lab1702 avatar Aug 28 '25 02:08 lab1702

Super annoying. Please fix.

nielsbosma avatar Sep 01 '25 14:09 nielsbosma

Super annoying. Please fix.

Hi, I found that in my case, this was happening because I had a Unix configuration in the additionalDirectories parameter of the .claude\settings.local.json file.

Updating it to the correct path prevented it from happening again.

Image

JhonHawk avatar Sep 03 '25 01:09 JhonHawk

Aha, is this maybe related to when you work on the same project using both Windows and Linux PCs? I've noticed the Windows version getting better at "knowing" whether it is running in Windows or Linux...

lab1702 avatar Sep 03 '25 19:09 lab1702

Aha, is this maybe related to when you work on the same project using both Windows and Linux PCs? I've noticed the Windows version getting better at "knowing" whether it is running in Windows or Linux...

Maybe when enabled this config (in webstorm plugin config)

Image

JhonHawk avatar Sep 04 '25 06:09 JhonHawk

I'm not running Windows in Linux or vice versa, but I've been using GitBash for Windows and this file is being created from time to time.

Funny thing is, I could not delete the file without elevated permission, but Claude code once found it and easily removed it on its own.

CreativeWarlock avatar Sep 04 '25 09:09 CreativeWarlock

Ask claude code to remove the "nul" file that it created. This worked for me.

jlrindal avatar Sep 19 '25 00:09 jlrindal

Ask claude code to remove the "nul" file that it created. This worked for me.

genius! - works for me

CJOgilvie avatar Sep 30 '25 12:09 CJOgilvie

I encountered the same issue with additional details that might help narrow down the root cause:

Trigger: Claude Code 2.0.8 was analyzing project file structure

File content (864 bytes):

$ cat nul
  File "<string>", line 1
    import os; from pathlib import Path; [print('  ' * (len(p.parts) - len(Path.cwd().parts)) + ('ā–’ā–’ā–’ā–’ā–’ā–’ ' if i < len(list(Path(root).parent.glob('*'))) - 1 else 'ā–’ā–’ā–’ā–’ā–’ā–’ ') + p.name) for root, dirs, files in os.walk('.') for i, p in enumerate([Path(root)] + [Path(root) / d for d in sorted(dirs)] + [Path(root) / f for f in sorted(files)]) if p.is_file() or (p.is_dir() and p \!= Path(root))]
                                                                                                                                                                                                                                                                                                                                                                                   ^
SyntaxError: unexpected character after line continuation character

This suggests Claude Code tried to generate a file tree visualization using a Python one-liner, which had a syntax error. The stderr was redirected to nul but created a physical file instead.

Specific code path: File tree analysis/project structure inspection

This might help pinpoint which part of the CLI codebase is causing the issue.

Additional note on file access:

The nul file can be read and deleted normally using Git Bash:

# Read content
cat nul

# Delete
rm nul

However, Windows native tools fail:

  • PowerShell: "Cannot find path" (even with UNC path \\?\...)
  • File Explorer: Shows file but properties are empty
  • Get-FileHash: "Path does not exist"

This confirms the issue is at the Win32 API semantic layer - Git Bash directly accesses NTFS and treats nul as a regular filename, bypassing Windows reserved name checks.

Workaround for users: If you encounter this issue, use Git Bash to remove the file:

rm nul

ClearPlume avatar Oct 06 '25 14:10 ClearPlume

This is ruining my commits on a regular basis. I use plastic for game dev and nul causes chaos on the filesystem and can absolutely corrupt the source control history.

brandon-reinhart avatar Oct 09 '25 14:10 brandon-reinhart

This suddenly started happening to me today when I was just working on a regular React app. I made some prompts to change the JSX and there was the nul file with no apparent reason. Some of the operations I did was removing a Unicode character in a TypeScript file, removing a redundant import, and just working on regular JSX. Now it always creates the nul file when I open VS Code, doesn't even require input from me. And I'm purely working on a Windows machine.

yorkaturr avatar Oct 13 '25 15:10 yorkaturr

Can confirm. Claude Code created a literal nul file during git merge operations on Windows with Git Bash. Appears to be using 2>nul (Windows CMD syntax) instead of 2>/dev/null in a Unix shell context.

yunlishao avatar Oct 17 '25 03:10 yunlishao

Can confirm with version 2.0.22

tvardero avatar Oct 19 '25 12:10 tvardero

Aurrgggghhhhh...

dougm1966 avatar Oct 22 '25 17:10 dougm1966

Very annoying bug to contend with during dev, while trying to save tokens -- I don't want to waste tokens asking Claude to clean up its mess.

ArcaneEngineer avatar Oct 27 '25 18:10 ArcaneEngineer

same here. Windows11 running in a powershell. The Claude CLI starts having errors once the NUL file is created. I'm trying to fix that wit a skill (remove-nul). But Claude has a hard time remembering its skills.

bittebak avatar Oct 29 '25 14:10 bittebak

Comfirmed issu in multiple projects. Same issue here. Windows 11 Powershell.

polachp avatar Nov 03 '25 17:11 polachp

Got it - null on each project folder. can't copy, hard to delete. created everytime when run claude code.

lightcomc avatar Nov 04 '25 08:11 lightcomc

I ended up writing a Python script to clean up all the folders:

#!/usr/bin/env python3
"""
NUL Files Removal Script for Windows

This script finds and removes files named 'nul' which are problematic on Windows.
'nul' is a reserved device name in Windows (like CON, PRN, AUX) and cannot be
manipulated using standard file operations.

The script uses Windows UNC path syntax (\\?\) to bypass the reserved name
restriction and safely remove these files.

Usage:
    python remove_nul_files.py [directory]

    If no directory is specified, defaults to the script's directory
"""

import os
import sys
from pathlib import Path

def find_nul_files(root_path, verbose=True):
    """
    Recursively search for files named 'nul'.

    Args:
        root_path: The root directory to search from
        verbose: Whether to print search progress (default: True)

    Returns:
        List of paths to 'nul' files found
    """
    nul_files = []

    if verbose:
        print(f"Searching for 'nul' files in: {root_path}")
        print("-" * 60)

    try:
        # Walk through all directories
        for dirpath, _, filenames in os.walk(root_path):
            # Check for files named 'nul'
            if 'nul' in filenames:
                nul_file_path = os.path.join(dirpath, 'nul')
                nul_files.append(nul_file_path)
    except Exception as e:
        print(f"Warning: Error during search: {e}")

    return nul_files

def remove_nul_files(nul_files):
    """
    Remove the specified nul files.
    Uses Windows UNC path syntax (\\?\) to handle reserved names like 'nul'.

    Args:
        nul_files: List of file paths to remove

    Returns:
        Tuple of (removed_count, error_count)

    Notes:
        - Uses UNC path prefix (\\?\) to bypass Windows reserved name restrictions
        - Handles symlinks and junctions that may point to the same physical file
        - Returns count of removed files and errors encountered
    """
    removed_files = []
    errors = []

    if not nul_files:
        return 0, 0

    print("\nRemoving files...")
    print("-" * 60)

    for nul_file_path in nul_files:
        try:
            # Use pathlib to get absolute path WITHOUT resolving symlinks/junctions
            path_obj = Path(nul_file_path)
            # Get absolute path without resolving symlinks (use absolute() instead of resolve())
            abs_path = str(path_obj.absolute())

            # Normalize backslashes
            abs_path = abs_path.replace('/', '\\')

            # Add \\?\ prefix for Windows long path / reserved name support
            # This bypasses the Windows reserved name check
            unc_path = f"\\\\?\\{abs_path}"

            os.remove(unc_path)
            removed_files.append(nul_file_path)
            print(f"āœ“ Removed: {nul_file_path}")
        except FileNotFoundError:
            # File might have been already deleted (symlink/junction pointing to same file)
            print(f"⊘ Already removed (symlink/junction): {nul_file_path}")
            removed_files.append(nul_file_path)
        except Exception as e:
            errors.append((nul_file_path, str(e)))
            print(f"āœ— Failed to remove: {nul_file_path}")
            print(f"  Error: {e}")

    # Summary
    print("-" * 60)
    print(f"\nSummary:")
    print(f"  Files removed: {len(removed_files)}")
    print(f"  Errors: {len(errors)}")

    if removed_files:
        print("\nRemoved files:")
        for file in removed_files:
            print(f"  - {file}")

    if errors:
        print("\nErrors:")
        for file, error in errors:
            print(f"  - {file}: {error}")

    return len(removed_files), len(errors)

def main():
    """Main execution function."""
    # Default to the directory where the script is located
    script_dir = os.path.dirname(os.path.abspath(__file__))
    target_dir = script_dir

    # Allow override via command line argument
    if len(sys.argv) > 1:
        target_dir = sys.argv[1]

    # Validate directory exists
    if not os.path.exists(target_dir):
        print(f"Error: Directory '{target_dir}' does not exist!")
        input("\nPress ENTER to close...")
        sys.exit(1)

    if not os.path.isdir(target_dir):
        print(f"Error: '{target_dir}' is not a directory!")
        input("\nPress ENTER to close...")
        sys.exit(1)

    print("=" * 60)
    print("NUL Files Removal Script")
    print("=" * 60)
    print(f"Target directory: {target_dir}")
    print("=" * 60)

    try:
        # First, find all nul files
        nul_files = find_nul_files(target_dir)

        if not nul_files:
            print("\nāœ“ No 'nul' files found!")
            input("\nPress ENTER to close...")
            sys.exit(0)

        # Display found files
        print(f"\nFound {len(nul_files)} 'nul' file(s):")
        print("-" * 60)
        for file in nul_files:
            print(f"  - {file}")
        print("-" * 60)

        # Ask for confirmation
        input(f"\nPress ENTER to delete these {len(nul_files)} file(s)... (or Ctrl+C to cancel)")
        print("")

        # Remove the files
        removed, errors = remove_nul_files(nul_files)

        # Final verification step
        print("\n" + "=" * 60)
        print("FINAL VERIFICATION")
        print("=" * 60)

        remaining_nul_files = find_nul_files(target_dir, verbose=False)

        if not remaining_nul_files:
            print("\nāœ“ SUCCESS: All 'nul' files have been removed!")
            print(f"  {removed} file(s) successfully deleted")
        else:
            print(f"\n⚠ WARNING: {len(remaining_nul_files)} 'nul' file(s) remaining:")
            for file in remaining_nul_files:
                print(f"  - {file}")

        print("\n" + "=" * 60)
        input("\nPress ENTER to close...")

        if errors > 0 or remaining_nul_files:
            sys.exit(1)
        else:
            sys.exit(0)
    except KeyboardInterrupt:
        print("\n\nOperation cancelled by user.")
        input("\nPress ENTER to close...")
        sys.exit(130)
    except Exception as e:
        print(f"\nUnexpected error: {e}")
        print(f"Error type: {type(e).__name__}")
        input("\nPress ENTER to close...")
        sys.exit(1)


if __name__ == "__main__":
    main()

hydropix avatar Nov 05 '25 07:11 hydropix

When will this be fixed? No matter how I write in claude md file to check the OS and to use correct cmd shell, it still makes them all the time.

This helps to clean up but still it can happen it makes a ton of them not just one.

# PowerShell script to delete all "nul" files created by mistake
# This uses .NET File.Delete with \\?\ prefix to bypass Windows reserved name handling

Write-Host "Finding all 'nul' files..." -ForegroundColor Yellow

$nulFiles = Get-ChildItem -Path "d:\yourfolderhere" -Filter "nul" -Recurse -Force -ErrorAction SilentlyContinue

$totalFiles = $nulFiles.Count
Write-Host "Found $totalFiles 'nul' files to delete" -ForegroundColor Cyan

$successCount = 0
$failCount = 0

foreach ($file in $nulFiles) {
    try {
        $fullPath = $file.FullName
        $extendedPath = "\\?\$fullPath"

        [System.IO.File]::Delete($extendedPath)
        $successCount++

        if ($successCount % 100 -eq 0) {
            Write-Host "Deleted $successCount / $totalFiles files..." -ForegroundColor Green
        }
    } catch {
        Write-Host "Failed to delete: $($file.FullName) - $_" -ForegroundColor Red
        $failCount++
    }
}

Write-Host ""
Write-Host "=== Deletion Complete ===" -ForegroundColor Green
Write-Host "Successfully deleted: $successCount files" -ForegroundColor Green
Write-Host "Failed: $failCount files" -ForegroundColor Red
Write-Host ""
Write-Host "Press any key to exit..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

csicky avatar Nov 05 '25 18:11 csicky

Yes it sucks and maybe I'm naive, but I just put it in the gitignore and have had no issues.

dougm1966 avatar Nov 05 '25 19:11 dougm1966

Yes it sucks and maybe I'm naive, but I just put it in the gitignore and have had no issues.

Interesting, I am worried if I do that maybe something in Windows might break?

Codex asked me to install WSL so maybe we could ask Claude to use that too, if it likes more to talk in Linux talk.

csicky avatar Nov 05 '25 19:11 csicky

Yes it sucks and maybe I'm naive, but I just put it in the gitignore and have had no issues.

Interesting, I am worried if I do that maybe something in Windows might break?

Codex asked me to install WSL so maybe we could ask Claude to use that too, if it likes more to talk in Linux talk.

Haven't had an issue at all.

When I first started using windsurf I was using WSL and it sucked. I finally got things sorted and I'm working straight with Windows.

I've been running 3 Claude Code terminal sessions on three different monitors non-stop for about 10 days.

I hit my limit about 30 minutes before the reset yesterday and today I hit my limit just over an hour before the reset. (I'm getting more efficient in my prompting)

I'm on the $100 a month plan and have been just rocking it.

Yeah, adding it to the gitignore was the simplest solution and have had no problems.

dougm1966 avatar Nov 05 '25 21:11 dougm1966