[BUG] claude update / install.ps1 fail with EEXIST mkdir on ReadOnly directories (bundled Bun bug) — corrects the diagnosis in #67692
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
claude update (and the native install.ps1) abort with EEXIST: file already exists, mkdir '<dir>' on directories that already exist and carry the NTFS ReadOnly attribute — the same bundled-Bun mkdir(..., {recursive: true}) bug already documented for /export in #80669 and for session-env in #37306 / #50773 / #59622.
The install/update code path is a separate, still-unguarded call site, and it is the worst-hit one: the failure is not degraded functionality but a hard inability to update or install at all.
Two distinct paths fail, in sequence:
<XDG_DATA_HOME>\claude\versions<XDG_STATE_HOME>\claude\locks
This report corrects the diagnosis in #67692. That issue (mine, closed as stale) attributed the failure to orphaned OneDrive Files-On-Demand placeholders — directory entries listed by dir but failing stat. That theory is wrong. On the machine here today:
- No orphaned placeholders were present. Every entry under
share\claude,share\claude\versions,state\claudeandbinreturned from bothdir /A /Benumeration andGet-Item -LiteralPath. The update still failed identically. - The
~/.local→ OneDrive directory symlink is irrelevant. SettingXDG_DATA_HOME/XDG_STATE_HOMEto the direct, non-symlinked OneDrive path produced the sameEEXISTon the same directory. - The ReadOnly attribute is the sole trigger, confirmed by bisect (below). OneDrive is only incidental: it stamps
Ron the directories it syncs, which is why the bug correlates with OneDrive in #67692 and #52161.
What Should Happen?
claude update should succeed against an existing directory regardless of its ReadOnly attribute, as Node's documented mkdir recursive semantics require.
Suggested fix — the same guard proposed for the session-env call site in #59622, applied to the installer/updater mkdirs:
if (!existsSync(dir)) await mkdir(dir, { recursive: true });
// or: await mkdir(dir, { recursive: true }).catch(e => { if (e.code !== 'EEXIST') throw e });
Longer term, bumping the bundled Bun past the fix for oven-sh/bun#34413 (closed upstream) removes this whole class of Windows EEXIST bugs at once.
Secondary: the remediation hints are dead ends for this failure. install.ps1 prints Try running with --force to override checks but does not forward the flag, and claude.exe install --force fails identically (#67692); claude update prints Try running "claude doctor" for diagnostics, which does not surface the ReadOnly attribute.
Error Messages/Logs
PS> claude update
Current version: 2.1.215
Checking for updates to latest version...
Updating to 2.1.219...
Error: Failed to install native update
Error: EEXIST: file already exists, mkdir 'C:\Users\<user>\.local\share\claude\versions'
Try running "claude doctor" for diagnostics
Same failure with the symlink removed from the path (XDG vars pointed at the real OneDrive location):
PS> $env:XDG_DATA_HOME="C:\Users\<user>\OneDrive\.local\share"
PS> $env:XDG_STATE_HOME="C:\Users\<user>\OneDrive\.local\state"
PS> claude update
Error: EEXIST: file already exists, mkdir 'C:\Users\<user>\OneDrive\.local\share\claude\versions'
Bisect — clearing ReadOnly on the first directory moves the error to the next one, then clearing both fixes it:
PS> (Get-Item "$env:USERPROFILE\.local\share\claude\versions" -Force).Attributes
ReadOnly, Directory, Archive, ReparsePoint
PS> attrib -R "$env:USERPROFILE\.local\share\claude\versions"
PS> claude update
Error: EEXIST: file already exists, mkdir 'C:\Users\<user>\.local\state\claude\locks' <- moved on
PS> attrib -R "$env:USERPROFILE\.local\state\claude" ; attrib -R "$env:USERPROFILE\.local\state\claude\*" /S /D
PS> claude update
Successfully updated from 2.1.215 to version 2.1.219
Control — stock Node v24.18.0 does not reproduce it on the exact same paths while they still had ReadOnly set (mode is 444, i.e. the R attribute is present and observable):
{"path":"C:\\Users\\<user>\\.local\\share\\claude\\versions","mkdir":"OK","stat":"OK dir=true mode=444","write":"OK"}
{"path":"C:\\Users\\<user>\\OneDrive\\.local\\share\\claude\\versions","mkdir":"OK","stat":"OK dir=true mode=444","write":"OK"}
{"path":"C:\\Users\\<user>\\.local\\state\\claude\\locks","mkdir":"OK","stat":"OK dir=true mode=444","write":"OK"}
Node succeeds where the shipped binary fails, which places the defect in the bundled runtime rather than in libuv generally — consistent with the Bun analysis in #80669.
Steps to Reproduce
- Windows 11, native install.
attrib +R "%USERPROFILE%\.local\share\claude\versions"(or let OneDrive stampRby keeping the XDG data/state dirs in a synced folder).- Run
claude updatewhen an update is actually available →EEXIST: file already exists, mkdir '...\share\claude\versions'. attrib -Rthe directory →claude updatesucceeds.
Step 3 needs a pending update; when already on the latest version the updater short-circuits before the mkdir.
Workaround for anyone hitting this:
attrib -R "%USERPROFILE%\.local\share\claude" & attrib -R "%USERPROFILE%\.local\share\claude\*" /S /D
attrib -R "%USERPROFILE%\.local\state\claude" & attrib -R "%USERPROFILE%\.local\state\claude\*" /S /D
claude update
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Claude Code Version
2.1.219 (Claude Code), native win32-x64
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
- Environment: Windows 11 Pro 10.0.26200, PowerShell 7, OneDrive with Files-On-Demand.
~/.localis a directory symlink to%USERPROFILE%\OneDrive\.localfor cross-desktop dotfile sync — but as shown above the symlink is not a factor. - Related: #80669 (
/export, same root cause, open), #67692 (this same installer/updater failure, misdiagnosed as orphaned placeholders, closed as stale), #37306 / #50773 / #59622 (~/.claudeandsession-env, closed as duplicate or not-planned), #52161, oven-sh/bun#34413. - After the fix, ReadOnly had not been re-applied to those directories within the following ~10 minutes, so this does not appear to be a tight loop with the sync engine — but the attribute will presumably return, and the update will break again, on any machine where a sync or backup tool stamps
R.
🤖 Diagnosis and report produced with Claude Code