[BUG] file named nul created on windows

Resolved 💬 184 comments Opened Aug 1, 2025 by rweijnen Closed Feb 27, 2026
💡 Likely answer: A maintainer (ant-kurt, collaborator) responded on this thread — see the highlighted reply below.

Environment

  • Platform (select one):
  • [ ] Anthropic API
  • [x] Other: Claude CLI
  • Claude CLI version: 1.0.62
  • Operating System: Windows <!-- specify version if known, e.g. Windows 11, Windows 10 -->
  • Terminal: <!-- e.g. Command Prompt, PowerShell, 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.

View original on GitHub ↗

184 Comments

github-actions[bot] · 11 months ago

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

phoenixtail26 · 11 months ago

I'm still experiencing this on version 1.0.72

rweijnen · 11 months ago

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: @.***>
Boh1 · 11 months ago

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.

craigvc · 11 months ago

Confirmed same issue

RadicalCaitlin · 10 months ago

I'm having the same issue.

JhonHawk · 10 months ago

Confirmed issue in the version: 1.0.90

lab1702 · 10 months ago

Just happened, claude code v1.0.95

nielsbosma · 10 months ago

Super annoying. Please fix.

JhonHawk · 10 months ago
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.

<img width="537" height="302" alt="Image" src="https://github.com/user-attachments/assets/4f33bba9-39f9-49a0-8dda-da09c2e06e75" />

lab1702 · 10 months ago

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...

JhonHawk · 10 months ago
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)

<img width="985" height="737" alt="Image" src="https://github.com/user-attachments/assets/42097743-a034-4267-85f2-6db9c754a6b6" />

CreativeWarlock · 10 months ago

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.

jlrindal · 10 months ago

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

CJOgilvie · 9 months ago
Ask claude code to remove the "nul" file that it created. This worked for me.

genius! - works for me

ClearPlume · 9 months ago

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
brandon-reinhart · 9 months ago

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.

yorkaturr · 9 months ago

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.

yunlishao · 9 months ago

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.

tvardero · 9 months ago

Can confirm with version 2.0.22

dougm1966 · 8 months ago

Aurrgggghhhhh...

ArcaneEngineer · 8 months ago

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.

bittebak · 8 months ago

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.

polachp · 8 months ago

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

lightcomc · 8 months ago

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

hydropix · 8 months ago

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()
csicky · 8 months ago

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")
dougm1966 · 8 months ago

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

csicky · 8 months ago
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.

dougm1966 · 8 months ago
> 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.

moosilauke · 8 months ago

Thank you for the sample PowerShell script, that did the trick for me. Wish Claude would stop creating NUL in the first place though.

nicthib · 8 months ago

Having the same issue on Windows. Even worse, if the nul file is pushed to the repo, cloning will fail:

git clone -b dev https://github.com/nicthib/jbam
Cloning into 'jbam'...
remote: Enumerating objects: 701, done.
remote: Counting objects: 100% (342/342), done.
remote: Compressing objects: 100% (250/250), done.
remote: Total 701 (delta 218), reused 202 (delta 88), pack-reused 359 (from 1)
Receiving objects: 100% (701/701), 18.06 MiB | 4.72 MiB/s, done.
Resolving deltas: 100% (416/416), done.
error: invalid path 'nul'
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'git restore --source=HEAD :/'
abdelrahman-mohammad · 8 months ago

If you're not able to delete the file, try this:

  1. Open Git Bash
  2. cd into the directory containing the nul file.
  3. run rm -rf <filename>

Source: https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/cannot-delete-file-folder-on-ntfs-file-system

csicky · 8 months ago

More than 3 months and still not fixed. Why not use Claude Code to fix Claude Code?

aidanhutch · 8 months ago

Just to confirm this issue is still happening in the latest build of Claude Code cli, as someone mentioned before its seems to be when doing bash etc in windows if there is command with '>value' and that might be a null value but in windows its a dos command for making a file i.e. 'dir . >filelist.txt' etc. Please see if some Claude dev can sort this, thanks. Great job on Claude code so far :-)

oddgames-david · 8 months ago

Happening with claude code vs extension. Really needs a fix, stops unity from opening.

nielsbosma · 8 months ago

I'm having the same issue. Created this PowerShell script to delete these files. https://github.com/nielsbosma/Scripts/blob/main/DeleteNul.ps1

millwheel · 8 months ago

I have a same issue.

After using Claude Code, The unknown 'nul' file was created and it can't be deleted.

git add . 
error: invalid path 'nul' error: 
unable to add 'nul' to index fatal: adding files failed
git rm nul 
fatal: pathspec 'nul' did not match any files

My OS is Windows.
It guess the claude code affect file system of windows and sometimes it creates trash file.
It is fatal issue because I can't controll git of the project any more.

csicky · 8 months ago
I have a same issue. After using Claude Code, The unknown 'nul' file was created and it can't be deleted. `` git add . error: invalid path 'nul' error: unable to add 'nul' to index fatal: adding files failed ` ` git rm nul fatal: pathspec 'nul' did not match any files `` My OS is Windows. It guess the claude code affect file system of windows and sometimes it create trash file. It is fatal issue because I can't controll git of the project any more.

Just run the PS script from higher in the comments. Also you can save it in the project folder then ask Claude to run it.

Ni2Be · 8 months ago

same issue here, very annoying.

allan-wright-ch · 8 months ago

Also experiencing this issue and is super annoying. Can't Claude just get this sorted out?

abdelrahman-mohammad · 8 months ago
Also experiencing this issue and is super annoying. Can't Claude just get this sorted out?

https://github.com/anthropics/claude-code/issues/4928#issuecomment-3517676629

rainy-london · 8 months ago

same issue.

timwkosatec · 7 months ago

if you have trouble deleting the nul file, open the directory with git bash and type rm nul
requires no administrator privileges

wickedmachinator · 7 months ago

yeah, super annoying :(

Jkith-dev · 7 months ago

Same issue, very annoying, I use this in command prompt:

DEL "\\.\C:\PATH-TO-NUL-FILE"

and it actually deletes it. Have it as a quick script i double click on my desktop.

tepesalexandru · 7 months ago

To temporarily fix this, open the Git Bash on Windows, type mv nul nul.json, and then rm nul.json to delete the file.

cizole · 7 months ago

also having this problem

qepri · 7 months ago

same issue, is ai breadcrumbing itself in the form of a bug?

enf0rc3 · 7 months ago

same issue, please solve.

Note: on windows you can remove by opening the folder in git bash, and then run rm nul

Dimonka2 · 7 months ago

In VSC it is possible delete those files via the folder view, but still annoying.

baslie · 7 months ago

Same annoying issue

zrovihr · 7 months ago

still a thing apparently.

ontisme · 7 months ago

still a thing apparently.

rjkborm · 7 months ago

Still a thing, it generated one for me just today

thefrederiksen · 7 months ago

Please get this fixed; it is happening a lot on Windows. I have had to write a background app that monitors my drives and deletes the nul files, but this is not a great solution.

devsynck · 7 months ago

Even after deleting, it's coming back for me within second

leewsimpson · 7 months ago

Still a problem more than four months later

DeVilAus · 7 months ago

Same issue for me. This is really annoying. Can we please get this addressed?

oddgames-david · 7 months ago

<img width="470" height="278" alt="Image" src="https://github.com/user-attachments/assets/8377300a-f687-4a5e-abb0-aa117eda2c3d" />

voxvanhieu · 7 months ago

I got the same issue

designbyian · 7 months ago

I wouldn't expect a quick fix for this because it would likely require fine tuning the model. Maybe they have tools that can change behavior in some other way, maybe not.

In the meantime the models respond fairly well to instructions (for example in claude.md) like:
Windows: use 2>/dev/null not 2>nul (causes bash to create literal file)

You might still have problems later in the context but for the most part that solves it

leewsimpson · 7 months ago

Can't they just build this directly into Claude code so it removes these
files automatically / blocks the agent from writing them.

On Tue, 9 Dec 2025 at 14:43, designbyian @.***> wrote:

designbyian left a comment (anthropics/claude-code#4928) <https://github.com/anthropics/claude-code/issues/4928#issuecomment-3630282686> I wouldn't expect a quick fix for this because it would likely require fine tuning the model. Maybe they have tools that can change behavior in some other way, maybe not. In the meantime the models respond fairly well to instructions (for example in claude.md) like: Windows: use 2>/dev/null not 2>nul (causes bash to create literal file) You might still have problems later in the context but for the most part that solves it — Reply to this email directly, view it on GitHub <https://github.com/anthropics/claude-code/issues/4928#issuecomment-3630282686>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAQIWHINVNFIVCDLA5QR6PT4AZHOHAVCNFSM6AAAAACC445NFGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTMMZQGI4DENRYGY> . You are receiving this because you commented.Message ID: @.***>
Pentadome · 7 months ago

workaround:

.claude/hooks/windows-nul-fix.js

import {  stdin } from "node:process";
import { rmSync } from "node:fs";
import path from "node:path";
import os from "node:os";

// workaround for https://github.com/anthropics/claude-code/issues/4928
if (os.platform() === "win32") {
  stdin.on("data", (data) => {
    const eventRaw = data.toString();

    if (!eventRaw || !eventRaw.startsWith("{")) {
      throw new Error("Event is missing");
    }

    const event = JSON.parse(eventRaw)

    rmSync(path.join(event.cwd, "nul"), { force: true });
  });
}

.claude/settings.json

{
  "hooks": {
    "PostToolUse": [
      {
		"matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/windows-nul-fix.js"
          }
        ]
      }
    ]
  }
}
1ngimar · 7 months ago

I'm having the same issue.

dromzeh · 7 months ago

also experiencing the same on 2.0.62 for the past couple days. using vsc or git bash in the repo dir seems to be the best way to remove it; still super tedious though

johnthatfield · 7 months ago

Experiencing in v2.0.65 still

Arputikos · 7 months ago

I have the same issue, it keeps creating it

SaltedDoubao · 7 months ago

Perhaps we could stipulate in CLAUDE.md that it should execute commands using pwsh or cmd? (I haven't tried it yet, so I don't know if it works)

MatevzFa · 7 months ago

This is still an issue in 2.0.70.

This is a general issue with how Claude (sometimes) generates Bash(...) tool uses on Windows. It will mix up Bash and cmd syntax. For example, it will generate

Bash(ls C:\path\to\directory 2>nul | findstr -i something)`

There are at least two issues with this:

  • backslash character (\) as path separator in Bash
  • 2>nul for stderr output redirection in Bash (instead of /dev/null)
Udit19-pixel · 7 months ago

Can confirm this issue remains unresolved in v2.0.71.

The "nul" file creation occurs with:

  • Generic commands (e.g., "/init")
  • Standard user prompts
  • Any command execution within the extension
This is still an issue in 2.0.70. This is a general issue with how Claude (sometimes) generates Bash(...) tool uses on Windows. It will mix up Bash and cmd syntax. For example, it will generate `` Bash(ls C:\path\to\directory 2>nul | findstr -i something) `` There are at least two issues with this: * backslash character (\) as path separator in Bash * 2>nul for stderr output redirection in Bash (instead of /dev/null`)
johnlester · 6 months ago

Same, created by /init in a mostly empty new project on Windows

revskill10 · 6 months ago

This is a very stupid bug.

markshapiro-cv · 6 months ago

Still an issue in 2.0.71

arti1117 · 6 months ago

Still an issue in 2.0.75

zsol · 6 months ago

Just to emphasize how annoying this is, while deleting these nul files can be worked around by using a UNC path as described above - if it somehow ends up in your git index or staging area, you can't checkout a different commit, stash, rebase, not even git reset --hard HEAD^.

I ended up setting up WSL and firing up a container to fix up my git local state.

SaltedDoubao · 6 months ago

@zsol You can actually run rm nul in git bash to delete this file.

mihend · 6 months ago

I had the same issue. Vibe fix:

<img width="343" height="213" alt="Image" src="https://github.com/user-attachments/assets/e50c59ee-69fd-4ca7-b6ee-2bfe95e8cf5e" />

garo-pro · 6 months ago

Issue persists on 2.0.76. However, @hydropix 's Python script fixed it. Appreciated!

Ben-CA · 6 months ago

I'm still getting a nul file created.

zmn-hamid · 6 months ago

shift delete helped me delete the file finally
edit: it deletes but gets immediately recreated

ltouro · 6 months ago

same issue here. Version 2.0.76 (Claude Code)

ilaiw · 6 months ago

Bug still happening!!
I had this nul file created 3-4 times in the past week.
Working with the latest Claude Code as an extension in VS Code.
I'm pretty sure this time it was created here:

Bash Check for .vscode folder
IN dir /b .vscode 2>nul | | echo "No .vscode folder"
OUT No .vscode folder

It's hard to delete, but this does the trick-
Open Powershell as admin.

cmd /c del /f /q "\\?\C:\Users\<PATH_TO_NUL_FILE>\nul"
RomainBitard · 6 months ago

Is there a configuration or something to prevent it from coming back ?

ilaiw · 6 months ago
Is there a configuration or something to prevent it from coming back ?

Not that I know of

lightfinesthour · 6 months ago

still a problem in version of today, it is a silly bug.

claude code in vs code:
2.0.75

gigarun · 6 months ago

Yes, claude should stop create reserved names. see https://github.com/anthropics/claude-code/issues/16604

Ben-CA · 6 months ago

I've lost track how many times I've deleted this nul file. (Shift + Delete)

ten24bytes · 6 months ago

This issue still exists. I'm using Claude Code in terminal on Windows 11.

I had to use the below command to delete it:
del "\\?\X:\path-to\actual-file\NUL"

gankudadiz · 6 months ago

thanks god,Shift + Delete is true

tombrewer-onwave · 6 months ago

This is rapidly becoming incredibly annoying. It causes things like generation of automatic commit comments (e.g. VS Co-pilot) to fail as it stumbles across these files. I have been using WSL (with "rm null") to get rid of them but they appear continuously and it's now beyond a joke.

Ditronian · 6 months ago

I have delete this thing at least 20 times per week since it breaks Unity... How is silly bug like this from August still around? Thank you people above for mentioning Shift - Delete, I've probably lost hours trying to remember cmd line commands that can actually delete this thing.

DomiOnline · 6 months ago

We are getting this also.

essovius · 6 months ago

no fix since Aug 1, 2025 , and now also these:

<img width="600" height="368" alt="Image" src="https://github.com/user-attachments/assets/697e1138-44c5-4c07-aa2e-9c994ecf16db" />

friefa · 6 months ago
I've lost track how many times I've deleted this nul file. (Shift + Delete)

I'm seeing the same behavior, but Shift + Delete is a workaround that worked for me, thank you!

literallytwo · 6 months ago

+1 (possibly, if this has not been fixed by the fix for tmpclaude files)

christianevaroa · 6 months ago
> I've lost track how many times I've deleted this nul file. (Shift + Delete) I'm seeing the same behavior, but Shift + Delete is a workaround that worked for me, thank you!

In my experience shift+delete won’t raise an error and the file will disappear from the list in explorer while you have it open, but if you leave the folder and then go back into it the nul file will still be there. I found several methods for deleting the nul file on google, most of which did not work. The one that worked for me was cmd as admin using the del command with the \\\\?\\ syntax that allows you to delete files with protected names.

xgreymx · 6 months ago

Still an issue, an a really annoying one.

CN-Scars · 6 months ago
这个问题依然存在,而且是一个非常恼人的问题。

Same

CN-Scars · 6 months ago
自从它导致 Unity 崩溃以来,我每周至少要删除它 20 次……这么个八月份就存在的愚蠢 bug 怎么还没消失?感谢楼上提到 Shift + Delete 的方法,我可能浪费了好几个小时试图记住能删除它的命令行命令。

Yes, it is indeed annoying. Of course, if you prefer to use a terminal like Git Bash or WSL, you can also remove it using the simple rm command.

nshkrdotcom · 6 months ago

Still happening on Windows 11 + Git Bash with Claude Code v2.1.7.

Empty nul file (0 bytes) created in the working directory alongside the tmpclaude-*-cwd temp files.

ltouro · 6 months ago

got way worse with the tmpclaude-*-cwd files

jay-pearson-net · 6 months ago

Having the same issues with 'nul' file creation and 'tmpclaude' files being generated.
None of the workarounds to delete the 'nul' files would work for me but I found this to work for anyone having the same issue...

  • Navigate to the file location in 7-zip file manager
  • Rename the 'nul' file to 'nul.txt'
  • Delete the file
RomainBitard · 6 months ago

still the case

kbecking · 6 months ago

Same issue. Any work around?

mallen-ez · 6 months ago

Ugh. All my .gitignores have 'nul' at the bottom...

Blake-Madden · 6 months ago

Shift + Delete deleted it, then it re-appears? It is impossible to get rid of this file. I guess add nul to your .gitignore files.

Blake-Madden · 6 months ago
Having the same issues with 'nul' file creation and 'tmpclaude' files being generated. None of the workarounds to delete the 'nul' files would work for me but I found this to work for anyone having the same issue... Navigate to the file location in 7-zip file manager Rename the 'nul' file to 'nul.txt' * Delete the file

I can confirm this worked for me on Windows 11

n4tt0u · 5 months ago

I am also reproducing this.
Claude Code v2.1.12

wouter51 · 5 months ago

Also having issues with this.

Antonytm · 5 months ago

The issue is still here....

@Blake-Madden Thank you for the workaround!

n4tt0u · 5 months ago

I was able to prevent nul files from being generated by adding the following to my .bashrc (usually located at ~/.bashrc):

# Automatically remove 'nul' file using DEBUG trap
trap '[[ -f nul ]] && rm -f nul' DEBUG
simplecodeai-amir · 5 months ago
Having the same issues with 'nul' file creation and 'tmpclaude' files being generated. None of the workarounds to delete the 'nul' files would work for me but I found this to work for anyone having the same issue... Navigate to the file location in 7-zip file manager Rename the 'nul' file to 'nul.txt' * Delete the file

Alternatively, in cmd:

rename \\.\C:\<PATH_TO_FILE>\NUL. delete.txt

del delete.txt

lioobayoyo · 5 months ago

fix it with PowerShell:

 Remove-Item -LiteralPath "\\?\C:\BaseFolder\nul" -Force

Needless to say, the issue is still there. Some attempts to add instruction to avoid this in Claude.md results in many more errors in command line, and claude ends up redoing what it knows, which leads to this nul file creation again. Please provide guidance / training for this, this a huge productivity and confidence hit in the tool for the team (need to explain, need to share the command to remove file, raise questions, etc...).
It's a bit like getting a good car to change your old motorcycle, but with the drawback that you have to stop the car every 5 min to recover something that was thrown down the road. The product makes us go faster, but the annoyance may be getting on our nerves enough to stop using it.

shyney7 · 5 months ago
I was able to prevent nul files from being generated by adding the following to my .bashrc (usually located at ~/.bashrc): # Automatically remove 'nul' file using DEBUG trap trap '[[ -f nul ]] && rm -f nul' DEBUG

Because this runs before every command, it adds overhead. 🥲

Claude Code just needs to stop redirecting output to nul instead of /dev/null (for git bash) or $null (for pwsh)

BarisGc · 5 months ago

i ask a cheap model to delete copied nul path :) for example: glm / minimax :)

kmgallahan · 5 months ago

Just use a hook that prevents it from happening, the output will also inform Claude to refrain:

*Edit: Don't bother correcting Claude, just fix bad tools calls directly: https://github.com/anthropics/claude-code/issues/4928#issuecomment-3848600448

Reyzerbit · 5 months ago

This bug causes massive issues with Windows as a whole. I get BSODs periodically because of this, as well as instances of not being able to even open the directory with my IDE because of its existence.

mirseo · 5 months ago

In my case, I managed to delete the nul files generated by Claude Code by opening the project in VS Code. While deleting them directly through the OS didn't work, I could see the failed command logs inside the files when opened in the editor. From there, I was able to delete them instantly using the Delete key (or the GUI).

qzark-com · 5 months ago
This bug causes massive issues with Windows as a whole. I get BSODs periodically because of this, as well as instances of not being able to even open the directory with my IDE because of its existence.

Exactly same, I don't know whom to blame, the RAMs or the claude code

CaMoTraX · 5 months ago

Yep having same issue. Using claude for unity coding help. This file corrupted my whole project and i couldn't find out why its suddenly broken until i've seen the nul file wich is recreated after removal.
This makes unity loop import and then breaks the import process. This needs to be fixed.

markshapiro-cv · 5 months ago

Ultimately what it boils down to is Claude Code doesn't really understand Windows. The nul file is only one example - several times a day, Claude has to go through several iterations of command line execution to do things on Windows, and it tries layering cmd + PowerShell + bash, and always messes up quotes, command separators, etc. The Windows implementation needs a lot of work.

greenpean · 5 months ago

The bug is still in version 2.1.29

404Utopia · 5 months ago

Small indie company that can be trusted with billions of dollars that can't even fix a bug reported half a year ago

n4tt0u · 5 months ago

Bug-fixing AI, get on this immediately. The point isn't how to delete 'nul' files. The problem is that Claude Code is spawning them constantly in the Windows environment.

shyney7 · 5 months ago

They don't care about windows. Target is Apple Vibe Coders and businesses that use apple. That's also why cowork only exists for mac. Just switch to Copilot CLI or Opencode if you are on windows. Sad but that's how it is right now.

The degradation of their models don't make it even worth it anymore anyway: https://marginlab.ai/trackers/claude-code/

Other problems on windows not getting attention: https://github.com/anthropics/claude-code/issues/5049

sckindvl · 5 months ago

still happening

Florian-Thake · 5 months ago

@kmgallahan on Windows a capital NUL also works fine, command > NUL
Claude Code needs to be instructed to use only capital NUL. This should work in git-bash as well.

Florian-Thake · 5 months ago

@n4tt0u you must rename it first: rename \\.\C:\..\NUL. deletefile.txt (note the dot after NUL!).
then just delete it del deletefile.txt

dougm1966 · 5 months ago

I don't know what all the hullabaloo is...
I just click it and hit delete and then confirm the delete. And, if you put it in your gitignore, it get's ignored.

ch-zacmo · 5 months ago

I doesn't always work to delete it from the explorer or from VSCode. Personnaly I just ask claude code to delete it and it work

kmgallahan · 5 months ago

@Florian-Thake I don't bother correcting Claude anymore via the previous script, it is a waste of time/context.

Instead I just fix a variety of Windows issues by modifying the tool calls directly:

*Note: the pwsh call is just to ensure powershell 7 is used instead of 5 on my system.

``` json
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python C:/Users/*/.claude/hooks/bash-syntax-corrector.py"
}
]
}
]
},


``` py
#!/usr/bin/env python3
"""
Bash Syntax Auto-Corrector Hook for Claude Code on Windows

Silently fixes common bash syntax errors before execution:
1. Windows backslash paths → forward slashes
2. PowerShell variables in double quotes → single quotes
3. Git options after file paths → reorder
4. NUL redirection → /dev/null
5. powershell → pwsh -NoProfile
6. Bare PowerShell cmdlets → wrap with pwsh
7. Missing -NoProfile flag → add it
"""
import json
import sys
import re


# PowerShell cmdlets that need pwsh wrapper when used bare
POWERSHELL_CMDLETS = {
    # Item cmdlets
    'Get-Item', 'Set-Item', 'New-Item', 'Remove-Item', 'Copy-Item',
    'Move-Item', 'Rename-Item', 'Clear-Item', 'Invoke-Item',
    'Get-ChildItem', 'Get-Content', 'Set-Content', 'Add-Content', 'Clear-Content',
    # Process/Service cmdlets
    'Get-Process', 'Start-Process', 'Stop-Process', 'Wait-Process',
    'Get-Service', 'Start-Service', 'Stop-Service', 'Restart-Service',
    # Object cmdlets
    'Select-Object', 'Where-Object', 'ForEach-Object', 'Sort-Object',
    'Group-Object', 'Measure-Object', 'Compare-Object', 'New-Object',
    # Output cmdlets
    'Write-Output', 'Write-Host', 'Write-Error', 'Write-Warning',
    'Write-Verbose', 'Write-Debug', 'Out-Null', 'Out-File', 'Out-String',
    # Path cmdlets
    'Test-Path', 'Split-Path', 'Join-Path', 'Resolve-Path', 'Convert-Path',
    'Get-Location', 'Set-Location', 'Push-Location', 'Pop-Location',
    # Variable cmdlets
    'Get-Variable', 'Set-Variable', 'New-Variable', 'Remove-Variable', 'Clear-Variable',
    # Web cmdlets
    'Invoke-WebRequest', 'Invoke-RestMethod',
    # Date/Time
    'Get-Date', 'Set-Date',
    # Other common cmdlets
    'Get-Command', 'Get-Help', 'Get-Member', 'Get-Module', 'Import-Module',
    'Get-Alias', 'Set-Alias', 'New-Alias',
    'Get-EventLog', 'Write-EventLog',
    'Get-WmiObject', 'Get-CimInstance',
    'ConvertTo-Json', 'ConvertFrom-Json', 'ConvertTo-Csv', 'ConvertFrom-Csv',
    'Export-Csv', 'Import-Csv',
    'Get-Clipboard', 'Set-Clipboard',
    'Get-Credential', 'Get-ExecutionPolicy', 'Set-ExecutionPolicy',
}


def fix_nul_redirection(command: str) -> str:
    """Replace >nul patterns with >/dev/null"""
    # Handle various NUL redirection patterns (case-insensitive)
    patterns = [
        (r'2>>\s*nul\b', '2>>/dev/null'),
        (r'>>\s*nul\b', '>>/dev/null'),
        (r'2>\s*nul\b', '2>/dev/null'),
        (r'1>\s*nul\b', '>/dev/null'),
        (r'>\s*nul\b', '>/dev/null'),
    ]
    for pattern, replacement in patterns:
        command = re.sub(pattern, replacement, command, flags=re.IGNORECASE)
    return command


def fix_backslash_paths(command: str) -> str:
    """Convert Windows backslash paths to forward slashes (outside pwsh commands)

    Bash quote behavior:
    - Single quotes: literal (no escape processing) - skip conversion
    - Double quotes: backslashes still escape characters - must convert
    - Unquoted: backslashes are escape characters - must convert
    """
    # Skip if this is already a pwsh/powershell command - those handle backslashes
    if re.match(r'^(pwsh|powershell)\s', command, re.IGNORECASE):
        return command

    # Pattern for Windows paths: C:\, D:\, etc.
    # Only skip paths inside single quotes (which preserve backslashes literally)
    result = []
    in_single_quote = False
    in_double_quote = False
    i = 0

    while i < len(command):
        char = command[i]

        if char == "'" and not in_double_quote:
            in_single_quote = not in_single_quote
            result.append(char)
            i += 1
        elif char == '"' and not in_single_quote:
            in_double_quote = not in_double_quote
            result.append(char)
            i += 1
        elif not in_single_quote:
            # Convert paths both unquoted AND inside double quotes
            # (bash interprets backslashes in both contexts)
            if i + 2 < len(command) and command[i+1] == ':' and command[i+2] == '\\':
                if command[i].isalpha():
                    # Found a Windows path, collect and convert it
                    path_start = i
                    i += 2  # Skip drive letter and colon
                    while i < len(command) and (command[i].isalnum() or command[i] in r'\-_.'):
                        i += 1
                    path = command[path_start:i]
                    result.append(path.replace('\\', '/'))
                    continue
            result.append(char)
            i += 1
        else:
            # Inside single quotes - preserve as-is
            result.append(char)
            i += 1

    return ''.join(result)


def fix_pwsh_variables(command: str) -> str:
    """Replace double quotes with single quotes for pwsh -Command arguments containing $variables"""
    # Match pwsh -Command "..." where ... contains $ variables
    pattern = r'(pwsh\s+(?:-NoProfile\s+)?-Command\s+)"([^"]*\$[^"]*)"'

    def replace_quotes(match):
        prefix = match.group(1)
        content = match.group(2)
        # Only change if there's a $ that looks like a variable (not escaped)
        if re.search(r'(?<!\\)\$\w', content):
            return f"{prefix}'{content}'"
        return match.group(0)

    return re.sub(pattern, replace_quotes, command, flags=re.IGNORECASE)


def fix_git_option_ordering(command: str) -> str:
    """Reorder git commands to put options before file paths"""
    # Only process git commands
    if not re.match(r'^git\s+', command):
        return command

    # Parse the git command
    parts = command.split()
    if len(parts) < 3:
        return command

    # git subcommand [args...]
    git_cmd = parts[0]  # "git"
    subcommand = parts[1]  # "diff", "log", etc.
    rest = parts[2:]

    # Separate options (start with -) from non-options
    options = []
    non_options = []

    i = 0
    while i < len(rest):
        arg = rest[i]
        if arg.startswith('-'):
            options.append(arg)
            # Check if this option takes a value (common ones)
            if arg in ('-m', '-C', '-n', '--format', '--pretty', '--author', '--since', '--until'):
                if i + 1 < len(rest) and not rest[i + 1].startswith('-'):
                    i += 1
                    options.append(rest[i])
        else:
            non_options.append(arg)
        i += 1

    # Check if reordering is needed (options after non-options)
    original_order = rest
    correct_order = options + non_options

    if original_order != correct_order and options and non_options:
        return f"{git_cmd} {subcommand} {' '.join(correct_order)}"

    return command


def fix_powershell_to_pwsh(command: str) -> str:
    """Replace 'powershell' with 'pwsh -NoProfile'"""
    # Match powershell at the start of command or after && / || / ;
    pattern = r'(^|&&|\|\||;)\s*powershell\s+'

    def replace_pwsh(match):
        prefix = match.group(1)
        separator = ' ' if prefix else ''
        return f"{prefix}{separator}pwsh -NoProfile "

    return re.sub(pattern, replace_pwsh, command, flags=re.IGNORECASE)


def fix_bare_cmdlets(command: str) -> str:
    """Wrap bare PowerShell cmdlets with pwsh -NoProfile -Command"""
    # Split on command separators (&&, ||, ;) and process each part
    # Use regex to split while keeping the separators
    parts = re.split(r'(\s*(?:&&|\|\||;)\s*)', command)

    modified = False
    result_parts = []

    for part in parts:
        # Skip separators and empty parts
        if not part.strip() or re.match(r'^(?:&&|\|\||;)$', part.strip()):
            result_parts.append(part)
            continue

        # Skip if this part is already a pwsh/powershell command
        if re.match(r'^(pwsh|powershell)\s', part.strip(), re.IGNORECASE):
            result_parts.append(part)
            continue

        # Check if this part starts with a known cmdlet
        words = part.strip().split()
        first_word = words[0] if words else ''

        if first_word in POWERSHELL_CMDLETS:
            # Wrap this part with pwsh
            result_parts.append(f'pwsh -NoProfile -Command "{part.strip()}"')
            modified = True
        else:
            result_parts.append(part)

    if modified:
        return ''.join(result_parts)
    return command


def fix_missing_noprofile(command: str) -> str:
    """Add -NoProfile flag to pwsh commands that don't have it"""
    # Match pwsh followed by -Command without -NoProfile
    pattern = r'^pwsh\s+(-Command\s)'

    if re.match(pattern, command, re.IGNORECASE):
        # Check if -NoProfile is already present
        if not re.search(r'-NoProfile', command, re.IGNORECASE):
            return re.sub(pattern, r'pwsh -NoProfile \1', command, flags=re.IGNORECASE)

    return command


def apply_all_corrections(command: str) -> str:
    """Apply all corrections in the right order"""
    original = command

    # Order matters: some corrections depend on others
    command = fix_nul_redirection(command)
    command = fix_powershell_to_pwsh(command)
    command = fix_bare_cmdlets(command)
    command = fix_missing_noprofile(command)
    command = fix_pwsh_variables(command)
    command = fix_backslash_paths(command)
    command = fix_git_option_ordering(command)

    return command


def main():
    try:
        input_data = json.load(sys.stdin)
    except json.JSONDecodeError as e:
        print(f"Hook error: Invalid JSON input: {e}", file=sys.stderr)
        sys.exit(1)

    tool_name = input_data.get("tool_name", "")
    tool_input = input_data.get("tool_input", {})
    command = tool_input.get("command", "")

    # Only process Bash commands
    if tool_name != "Bash" or not command:
        sys.exit(0)

    corrected = apply_all_corrections(command)

    # If corrections were made, return updatedInput
    if corrected != command:
        output = {
            "hookSpecificOutput": {
                "hookEventName": "PreToolUse",
                "permissionDecision": "allow",
                "updatedInput": {
                    "command": corrected
                }
            }
        }
        print(json.dumps(output))

    sys.exit(0)


if __name__ == "__main__":
    main()
HerrZinfarkt · 5 months ago

Same issue here. I couldn’t delete the nul file either.

I was finally able to remove it using WSL. Simply running rm nul worked — no sudo required and no error messages.

fadingsignal · 5 months ago

Ran into this just now, used WinRar to archive + 'delete file after' to get rid of it.

Eerrikki · 5 months ago

Quirk: Claude Code Creates nul Files on Windows

  • Discovered: 2025-02-05
  • Location: Any directory where Claude Code runs Bash commands
  • Behavior: Claude Code's Bash tool uses Unix-style /dev/null redirection which Windows interprets as creating a literal file named nul. These files block rmdir and cause "Access denied" errors. Standard deletion methods (del, Remove-Item, Test-Path) fail because Windows intercepts the reserved name.
  • Workaround: Use PowerShell with .NET and extended path prefix: [System.IO.File]::Delete("\\?\C:\full\path\nul"). Alternative: WSL rm, 7-Zip archive+delete, or rename trick ren \\.\path\NUL. temp.txt.
  • Domain: claude
  • Confidence: high (known bug #4928, confirmed deletion method works)

---

Quirk: Glob Tool Reports Phantom nul Files on Windows

  • Discovered: 2025-02-05
  • Location: Glob tool pattern matching
  • Behavior: Glob pattern **/nul or **/NUL matches Windows reserved device names in every directory, reporting them as if they were real files. This causes false positives - Claude may dismiss real nul files as "phantoms" when diagnostic tools like Test-Path also fail to find them.
  • Workaround: Don't trust Glob for nul file detection. Confirm actual files via build script errors ("Access denied" for nul) or directory listing. If something says "Access denied" for nul, the file IS real.
  • Domain: claude
  • Confidence: high (caused incorrect initial diagnosis in this session)
Florian-Thake · 5 months ago

@kmgallahan Thank you for providing this detailed script! Yes, better use some more CPU time as to waste tokens/reasoning and context.
But still, its a shame that such amount of workaround scripting code is needed at all - for easy tasks like invoking a shell script.

halillgolcuk · 5 months ago

We ran into the same issue on Windows.

Claude created a file/folder named nul inside the repo.
This cannot be deleted via Explorer, CMD, PowerShell, \\?\ paths,
robocopy, git clean, or even by asking Claude itself to delete it.

The ONLY thing that worked was opening Git Bash in the repo folder and running:

-- rm nul

Git Bash (POSIX layer) bypasses Windows reserved device-name handling,
while Win32 APIs refuse to touch NUL.

calebrussel77 · 5 months ago

You can delete nul files by opening VS Code, locate it, then press Shift + delete. It will automatically delete it.

khoa002 · 5 months ago
I don't know what all the hullabaloo is... I just click it and hit delete and then confirm the delete. And, if you put it in your gitignore, it get's ignored.

The hullabaloo is about something happening when it shouldn't. The suggestion is appreciated but don't trivialize the issue that needs to be addressed.

That be said, I followed your suggestion and added it to .gitignore, but all that does is just mask the problem, not resolve it.

L0rdS474n · 5 months ago

I’m seeing this as well on Windows.

Claude Code version: 2.1.37

Behavior: a literal file named nul appears in the working directory as soon as Claude performs file operations (create/update/delete files).

Impact: any folder containing this nul entry becomes painful/near-impossible to delete with normal PowerShell rm/Remove-Item (needs \\?\ path prefix workarounds), and it pollutes multiple project folders quickly.

This happens consistently for me after the first set of file writes/edits in a directory

sandscap-sc · 5 months ago

Another concern is that Claude starts repeatedly trying to delete rm "/nul" in different ways which has the potential of running incorrectly and removing a lot more than intended.

DennisJansenDev · 5 months ago

Yeah same on windows here, using Remove-Item -LiteralPath now with \\\\?\ path, this works, but it is still cumbersome to do this the whole time.

Remove-Item -LiteralPath "\\?\C:\repos\nul"

pablo-botella · 5 months ago

+1 — Still happening on Windows 10 (26200.7623). Found 4 nul files scattered across subdirectories after a session. Had to use Python with \?\ extended path syntax to delete them since they can't be removed normally.

RyanWF73 · 5 months ago
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.

Nice idea! Couldn't delete normally or add a prefix, etc, this did the trick through.

cicioflaviu · 5 months ago

Same here, on Windows 11
Back to Claude Code on WSL

Teyk0o · 5 months ago

Tip: delete it from WSL and add it to your .gitignore until we have a fix.

Yuerchu · 5 months ago

I asked claude to explore this issue, he told me:

Root Cause Analysis: nul File Creation on Windows

The Core Issue: Windows 11 24H2 Behavior Change

Windows 11 24H2 (build 26100+) removed the legacy restriction on reserved device names (NUL, CON, PRN, etc.). This is a breaking change from decades of Windows behavior:

| Operation | Windows 10 & earlier | Windows 11 24H2+ |
| :--- | :--- | :--- |
| fs.openSync('nul', 'w') | Opens NUL device (data discarded) | Creates a real file named nul |
| fs.openSync('\\\\.\\nul', 'w') | Opens NUL device | Opens NUL device (still works) |
| fs.openSync(os.devNull, 'w') | Opens NUL device | Opens NUL device (still works) |

Verified on Windows 11 build 26200:

const fs = require('fs');
const os = require('os');

// THIS CREATES A REAL FILE on Win11 24H2+
fs.openSync('nul', 'w');  // → creates ./nul (0 bytes)

// This is correct - uses UNC device path
fs.openSync(os.devNull, 'w');  // os.devNull = '\\\\.\\nul' → no file created

---

Where It Happens in Claude Code

Claude Code is compiled as a Bun binary. Somewhere in the Bun runtime or Claude Code's bundled cli.js, bare nul is being used as a file path instead of \\.\nul (i.e., os.devNull). This likely occurs in:

  1. stdio: "ignore" handling in Bun's child_process implementation — when spawning subprocesses, the runtime needs to redirect ignored streams to the null device.
  2. Error handling paths during tool execution — multiple users report the file appears specifically when tools throw errors.
  3. Ripgrep native addon (ripgrep.node) output handling — the Glob tool triggers this frequently.

The code worked on older Windows because the OS itself intercepted any access to nul and routed it to the NUL device. On Windows 11 24H2, that safety net is gone.

---

Fix

All occurrences of bare nul used as a file path must be replaced with os.devNull (\\.\nul), which is the UNC device path that correctly addresses the NUL device on all Windows versions. This may require fixes in both:

  • Claude Code's source (the cli.js bundle)
  • The Bun runtime itself (if the issue is in Bun's child_process or stdio internals)

---

References

eried · 5 months ago

Makes no sense that Windows 11 allows the creation now... but not the deletion via explorer 😣

ant-kurt collaborator · 5 months ago

We've made some adjustments in Claude Code 2.1.42 - let us know if this is still occurring

jeremy685 · 5 months ago

I solved the issue of committing to git by adding the file nul to the .gitignore

lightfinesthour · 5 months ago
I solved the issue of committing to git by adding the file nul to the .gitignore

That will still leave the actual file there...

ChaseSunstrom · 4 months ago
We've made some adjustments in Claude Code 2.1.42 - let us know if this is still occurring

The issue is still occurring in v2.1.45

lioobayoyo · 4 months ago
We've made some adjustments in Claude Code 2.1.42 - let us know if this is still occurring

no significant change noticed. nul files still getting quickly created yesterday & today at root folder and in some subfolders depending on the mood of the tools.

rweijnen · 4 months ago

I wrote a PreToolUse hook to prevent nul, and other reserverd file names creation.
Also fixes up the constant windows path mangling as Claude just keeps messing up forward, backwards slash and (argument) escaping under Windows. Also takes care of using $ in eg PowerShell oneliners.

Feel free to give it a go: https://github.com/rweijnen/claude-hooks

kataras · 4 months ago

Why still this not fixed?

murphymj5209 · 4 months ago

confirmed still not working; i would like some way to delete the file, if possible also.

DjakaTechnology · 4 months ago

Seems the only way to remove it is by deleting .claude folder in same folder as nul. WIthout deleting it, the file keep appearing

Captain-Aito · 4 months ago
Seems the only way to remove it is by deleting .claude folder in same folder as nul. Without deleting it, the file keep appearing.

I did all that only folder and nul file inside, tried everything it comes right back after force deleting, I removed WSL, docker desktop, and it still keeps popping up.

Florian-Thake · 4 months ago

For all who still have problems to delete nul.
From Windows cmd just issue

rename \\.\C:\..\NUL. deletefile.txt (note the dot after NUL!).
then just delete it del deletefile.txt

From git-bash a simple rm should do the job as well.

If you don't want to create a hook for claude code to prevent this to happen, the global CLAUDE.md is a good place to prevent nul files to be created:

- For redirect output to null always use /dev/null/ when invoking from git-bash. Never use nul inside git-bash since this may produce an unwanted 'nul' file in the directory which needs special treatment for deletion.
murphymj5209 · 4 months ago

i used del "\\?\C:\Users\michael\Desktop\nul*" to get this to work, finally done with this annoying problem. win 11, whatever current is for the release.

Captain-Aito · 4 months ago
For all who still have problems to delete nul. From Windows cmd just issue rename \\.\C:\..\NUL. deletefile.txt (note the dot after NUL!). then just delete it del deletefile.txt From git-bash a simple rm should do the job as well. If you don't want to create a hook for claude code to prevent this to happen, the global CLAUDE.md is a good place to prevent nul files to be created: > - For redirect output to null always use /dev/null/ when invoking from git-bash. Never use nul inside git-bash since this may produce an unwanted 'nul' file in the directory which needs special treatment for deletion.

Thanks!

Captain-Aito · 4 months ago
i used del "\\?\C:\Users\michael\Desktop\nul*" to get this to work, finally done with this annoying problem. win 11, whatever current is for the release.

Thank you

Captain-Aito · 4 months ago
We've made some adjustments in Claude Code 2.1.42 - let us know if this is still occurring

I hope to remember to test this but I've already moved everything into Linux containers now. I will see what happens when I make scripts on windows without using any hooks and if it happens again I will drop a comment.

Captain-Aito · 4 months ago
I solved the issue of committing to git by adding the file nul to the .gitignore

That's noise. Not a solution.

JaieParker · 4 months ago

This is still an issue I have had to create a hook to defend against this
Claude Code v2.1.59
One of my errors:
Bash(cd
/c/Users/JaieChamsoft/.claude/extensions/AIDLC-Web && cat ../../aidlc/intents/aidlc-dashboard-ui/units/UNIT-002-core-views/BOLT-CX1-STATE.md 2>/dev/null | he…)
⎿ Error: PreToolUse:Bash hook error: [$USERPROFILE/.claude/hooks/aidlc-host-publish/Aidlc.Host.exe validate]: Redirect to /dev/null blocked - let errors display

alongot · 4 months ago

Still having the same issue on my windows system with the latest version of claude code/vs code

Jevzo · 4 months ago

Still having the same issue. On windows you can simply delete it with a wsl terminal or gitbash. Just rm -f nul in the project dir. Still not fixed is crazy.

rweijnen · 4 months ago

@bcherny I couldn't find anything specific in the release notes regarding a fix for nul file creation so I'm wondering why you closed the issue?

marcindulak · 4 months ago

@bcherny please when closing issues, release the change first, publish the changelog linking from the changelog to the issue, and also consider posting a comment into the issue to inform the issue subscribers.

This type of process was tried in https://github.com/anthropics/claude-code/issues/17600#issuecomment-3912518825 and the changelog for 2.1.45 and 2.1.47 includes links to issues https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#2147.

natthapolvanasrivilai · 4 months ago

Hello why is this closed? Still generating 'NUL' file on 2.1.63

RDjarbeng · 4 months ago

I came here because I experienced this same issue using claude sonnet 4.6. Why is this closed?

Captain-Aito · 4 months ago
I came here because I experienced this same issue using claude sonnet 4.6. Why is this closed?

If you can't differentiate between a model number version and actual software version. Please just uninstall.

RDjarbeng · 4 months ago
If you can't differentiate between a model number version and actual software version. Please just uninstall.

Sorry not a helpful solution. 🙄

Captain-Aito · 4 months ago
> If you can't differentiate between a model number version and actual software version. Please just uninstall. Sorry not a helpful solution. 🙄

Sorry. You're making noise. Pointless. Read more comment less.

Captain-Aito · 4 months ago
> If you can't differentiate between a model number version and actual software version. Please just uninstall. Sorry not a helpful solution. 🙄

!image

I think you need a lot of help from real experts here. Your website security rating is F or if it could go lower it would.

Stop faking it!

rweijnen · 4 months ago

Let's please keep the focus on the issue.

Captain-Aito · 4 months ago
Let's please keep the focus on the issue.

Well you pretty much solved it. Thank you again.

rweijnen · 4 months ago
Bash Syntax Auto-Corrector Hook for Claude Code on Windows Silently fixes common bash syntax errors before execution: 1. Windows backslash paths → forward slashes 2. PowerShell variables in double quotes → single quotes 3. Git options after file paths → reorder 4. NUL redirection → /dev/null 5. powershell → pwsh -NoProfile 6. Bare PowerShell cmdlets → wrap with pwsh 7. Missing -NoProfile flag → add it

The -NoProfile is a nice addition, I've added this to my claude code hooks collection: https://github.com/rweijnen/claude-hooks

Thanks for sharing @kmgallahan

shyney7 · 4 months ago
> Bash Syntax Auto-Corrector Hook for Claude Code on Windows > > Silently fixes common bash syntax errors before execution: > 1. Windows backslash paths → forward slashes > 2. PowerShell variables in double quotes → single quotes > 3. Git options after file paths → reorder > 4. NUL redirection → /dev/null > 5. powershell → pwsh -NoProfile > 6. Bare PowerShell cmdlets → wrap with pwsh > 7. Missing -NoProfile flag → add it The -NoProfile is a nice addition, I've added this to my claude code hooks collection: https://github.com/rweijnen/claude-hooks Thanks for sharing @kmgallahan

For me the -NoProfile would break things since I've set it up to load cached path variables containing the MSVC BuildTools Toolchain without slowing down the startup of pwsh. This way I dont need to load them with VsDevCmd.bat that is significantly slower.

kmgallahan · 4 months ago

@rweijnen My hook has changed a bit as edge cases crop up: https://gist.github.com/kmgallahan/cf44f50293901c7d4034b21b52c5804f

rweijnen · 4 months ago
> > Bash Syntax Auto-Corrector Hook for Claude Code on Windows > > Silently fixes common bash syntax errors before execution: > > > > 1. Windows backslash paths → forward slashes > > 2. PowerShell variables in double quotes → single quotes > > 3. Git options after file paths → reorder > > 4. NUL redirection → /dev/null > > 5. powershell → pwsh -NoProfile > > 6. Bare PowerShell cmdlets → wrap with pwsh > > 7. Missing -NoProfile flag → add it > > > The -NoProfile is a nice addition, I've added this to my claude code hooks collection: https://github.com/rweijnen/claude-hooks > Thanks for sharing @kmgallahan For me the -NoProfile would break things since I've set it up to load cached path variables containing the MSVC BuildTools Toolchain without slowing down the startup of pwsh. This way I dont need to load them with VsDevCmd.bat that is significantly slower.

In my hooks every fix can be disabled in the config.json individually - good to know, if this is a common it's perhaps best to make it off by default (but so far you're the first/only)

4laoshiren · 4 months ago

For anyone still struggling with undeletable folders caused by nul files, I made a small tool called nonul that might help.

It replaces the folder "Delete" option in the Windows Explorer right-click context menu so that it can handle nul files automatically. Once installed, right-click Delete just works — even on folders containing nul files. Supports both one-liner install and Scoop.

Hope it helps! If you find it useful, a star on the repo would be much appreciated :)

github-actions[bot] · 3 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.