EBADF: bad file descriptor error on history.jsonl.lock (Windows race condition)

Resolved 💬 6 comments Opened Dec 29, 2025 by pgb123au Closed Feb 28, 2026

Description

Intermittent EBADF: bad file descriptor error occurs on Windows when Claude Code attempts to resolve the path of the history lock file.

Error Message

This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
Error: EBADF: bad file descriptor, realpath 'C:\Users\peter\.claude\history.jsonl.lock'
    at async realpath (node:internal/fs/promises:1164:10)
    at async mi1._addToNodeFs (file:///C:/Users/peter/AppData/Roaming/npm/node_modules/@anthropic-ai/claude-code/cli.js:448:10239)

Environment

  • OS: Windows 11
  • Claude Code Version: 2.0.76
  • Node.js: (bundled with Claude Code)

Root Cause Analysis

This appears to be a race condition where:

  1. A lock file (history.jsonl.lock) is created
  2. realpath() is called asynchronously to resolve its path
  3. The lock file is deleted before realpath() completes
  4. Node.js returns EBADF because the file descriptor is no longer valid

What Was Tried (Did NOT Fix)

  • Adding Windows Defender exclusion for ~/.claude folder (exclusion was already present)
  • Checking file permissions (all correct)
  • Clearing stale .lock files

Workaround That Helped

Trimming history.jsonl to reduce file size/lock contention:

tail -100 ~/.claude/history.jsonl > ~/.claude/history.jsonl.tmp && mv ~/.claude/history.jsonl.tmp ~/.claude/history.jsonl

Suggested Fix

The async realpath() call should be wrapped in a try-catch, or the lock file existence should be verified before calling realpath(). Alternatively, use synchronous realpathSync() for lock file operations to avoid the race condition.

Reproduction

Occurs intermittently during normal Claude Code usage on Windows. More frequent when history.jsonl is large (800+ lines).

View original on GitHub ↗

This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗