[BUG][Windows] Task tools (TaskCreate/TaskUpdate) wedged by EPERM on lock-dir rmdir — transient AV handle + orphaned .lock.lock blocks all later calls
Status Open
Maintainer reply None cached
Workaround ✓ Mentioned in description ↑
Activity 0 comments · opened Jul 24, 2026
Summary
The built-in Task tools (TaskCreate / TaskUpdate) persistently fail on Windows with:
EPERM: operation not permitted, rmdir 'C:\Users\<user>\.claude\tasks\<session-uuid>\.lock.lock'
EPERM: operation not permitted, rmdir 'C:\Users\<user>\.claude\tasks\<session-uuid>\1.json.lock'
Once it starts happening, every subsequent Task tool call in the session fails, making the task tools unusable. We have been reproducing this daily for ~6 weeks (orphaned lock dirs found in 36 of 91 session dirs, oldest 2026-06-12).
Environment
- Claude Code Desktop app on Windows 11 Pro (10.0.26200)
~/.claudeon local NTFS (not OneDrive/network)- Trend Micro (ウイルスバスター) real-time AV active
Investigation findings (live-reproduced and instrumented)
The task store uses mkdir-based locking (proper-lockfile style): lock = mkdir <target>.lock, unlock = rmdir. Two lock kinds are affected: the session-dir lock (.lock.lock) and per-task file locks (<n>.json.lock).
- EPERM occurs only on the unlock
rmdir— writes always succeed. After a failing TaskCreate,1.jsonexists with the full task; after a failing TaskUpdate, the new status is already persisted. So there is no data loss — the tool call just reports failure. - The blocking handle is transient. Immediately after the harness gets EPERM, a plain
os.rmdir()from Python on the same dir succeeds. Something (AV real-time scan is the prime suspect) holds a handle on the freshly-created lock dir for a moment, exactly when the harness tries to remove it. - Not reproducible outside the harness. 400 cycles of bare
mkdir → (write json) → rmdirfrom Python in the same directory produced 0 failures, suggesting the interference is selective to the Claude node process's file operations (process-triggered AV scanning). - The persistent breakage is caused by the orphaned lock dir, not by the EPERM itself: once
.lock.lockis left behind, subsequent lock acquisition fails, so all later Task calls in the session fail. Removing stale lock dirs immediately restores the tools (verified: TaskList/TaskUpdate succeed right after cleanup). TaskUpdate {status: "deleted"}returns a plainFailed to delete task(likely the same underlying EPERM swallowed — the task json is not removed).
Suggested fixes
- Retry
rmdiron WindowsEPERM/EBUSYwith short backoff (the classic rimraf/graceful-fs Windows workaround). Given the handle is gone within seconds, 2-3 retries would eliminate virtually all failures. - Treat a stale lock dir (mtime older than a few seconds/minutes) as reclaimable instead of failing lock acquisition, so an orphan from a previous crash/EPERM cannot permanently wedge the session's task store.
- Optionally: don't surface unlock-phase EPERM as a tool-call failure when the write itself committed (currently it reports failure for an operation that actually succeeded).
Workaround for other users
Periodically remove stale lock dirs:
python -c "import os,glob,time; base=os.path.expanduser('~/.claude/tasks'); now=time.time(); [os.rmdir(p) for p in glob.glob(os.path.join(base,'*','.lock.lock'))+glob.glob(os.path.join(base,'*','*.json.lock')) if os.path.isdir(p) and (now-os.path.getmtime(p))/60>5]"
Related issues
- #49984 — session-env dir lock requires manual rmdir to unstick Bash tool on Windows (same structural pattern: mkdir-based lock whose teardown fails and then wedges the feature)
- #46482 — EBUSY on
.claude.jsonwith concurrent sessions on Windows