Windows: Claude Code reads a stale snapshot of %APPDATA%, silently returning wrong file contents
Claude Code reads a stale snapshot of %APPDATA%, silently returning wrong file contents
Summary
In a Claude Code session on Windows, part of the filesystem is live and shared with the user,
and part is a stale snapshot — with nothing indicating which is which. Reads against the
snapshot succeed and return plausible but outdated data, so Claude reaches confident,
wrong conclusions about the user's files and argues them.
C:\Projects\...(the repo) — live. Edits, git status, commits and pushes all work, and
edits made by the user in their own editor are visible to Claude.
C:\Users\<user>\AppData\Roaming\...— stale snapshot, frozen ~10 days before the session.
This is not a one-off. It has recurred across multiple sessions and has produced a *persistent
false root cause* in Claude's saved notes, which was then reused in a later session (details below).
Environment
- Claude Code, Windows 11 Home 10.0.26200
- Sessions affected: at least 2026-08-03 and 2026-08-04
- Snapshot frozen at 2026-07-25 08:33:03 — the same date in every session, so this is a
persistent stale mount, not transient caching
- Reproduced via both the PowerShell tool and the Bash (Git Bash) tool
- Also reproduced with
dangerouslyDisableSandbox: true
Concrete case
The user ran dotnet user-secrets set 'ConnectionStrings:MyDb' '<value>' --project <path> in
their own terminal to update a local dev database connection string. Claude could not see the
change at all.
Same absolute path, $env:APPDATA resolving identically on both sides
(C:\Users\<user>\AppData\Roaming):
| Attribute | Claude sees | User's Explorer (Properties) |
|---|---|---|
| Size | 178 bytes | 222 bytes |
| Created | 25 Jul 2026, 8:33:03 am | 26 Jul 2026, 3:07:46 pm |
| Modified | 25 Jul 2026, 8:33:03 am | 4 Aug 2026, 10:33:37 pm |
The differing creation date and size are the key evidence. A stale metadata cache could
explain a wrong modified date; it cannot explain a different creation time and a different
length. These are two different files at the same path.
Verified with the user's own command, three path forms ($env:APPDATA, uppercase C:\,
lowercase c:\), sandbox on and off — identical result every time.
Recurrence, and how it compounded
- 2026-08-03. Same symptom. Claude concluded the user's
dotnet user-secrets set"passed an
empty value because an environment variable was unset in that shell", and wrote that into its
persistent memory as an established fact, along with the advice "check the store's mtime before
booting; if it still says 25 July, don't bother."
- 2026-08-04. Claude read that note, trusted it, and repeated the same wrong diagnosis to the
user — asserting their command had failed and proposing new incorrect causes (PowerShell
semicolon splitting, variable expansion). The user had to produce a screenshot of the Windows
file Properties dialog to disprove it.
Both recorded conclusions were artefacts of this bug:
- "The write never reached the store" — false; it reached the user's store, which Claude cannot see.
- "Check the store's mtime" — actively misleading; the mtime Claude sees is the snapshot's and is
permanently 25 July regardless of what the user does.
So the failure mode is self-reinforcing: bad data produces a wrong root cause, the wrong root cause
gets persisted, and the next session starts from it rather than rediscovering the problem fresh.
Steps to reproduce
- Start a Claude Code session on a Windows project.
- In a separate terminal, outside Claude, write a file under
%APPDATA%— e.g.
dotnet user-secrets set ..., or simply create %APPDATA%\fs-test.txt.
- Ask Claude to read it:
Get-Item "$env:APPDATA\fs-test.txt" | Select-Object FullName, LastWriteTime, Length
- Claude reports stale content, an old timestamp, or that the file does not exist.
Expected
Either Claude sees the same filesystem the user does, or a read against a non-live path fails
loudly / is clearly labelled as a snapshot.
Actual
Reads succeed and return stale data with no warning. Nothing distinguishes a live path from a
snapshotted one.
Impact
- Silent wrong answers, repeatedly, across sessions. This is the core problem. Claude is not
blocked — it is confidently incorrect, and it argues the point because its evidence looks solid.
The user is placed in the position of having to disprove their own tooling with screenshots.
- It corrupts Claude's persistent memory. A wrong root cause derived from snapshot data gets
saved and reused, so the cost is paid again in later sessions and the diagnosis drifts further
from the truth each time. This is the most damaging consequence and the reason the issue is not
self-limiting.
- Child processes inherit the stale view.
dotnet run— a separate process, launched with the
sandbox disabled — read the snapshot's old connection string and connected to the wrong database
host. So this is not confined to Claude's own file reads.
dangerouslyDisableSandboxdoes not escape it, which makes it present as a filesystem
problem rather than a sandbox policy, and sends debugging in the wrong direction.
- Breaks the documented workflow for .NET local development.
dotnet user-secretsis
Microsoft's standard mechanism for holding dev credentials outside the repo, and it stores them
under %APPDATA%. Claude cannot see or use them, so it cannot run the app locally — and the
obvious workaround (putting the credential in a settings file in the repo) is precisely what
must not be done. In this project that would violate an explicit "no secrets in the repo" rule.
Open question
Does this also affect C:\Users\<user>\.claude\ (profile root, not AppData)? Claude's persistent
memory files live there. If that subtree is snapshotted too, memory written during a session may
never reach the user's real profile — which would make impact (2) worse still, and would be silent
in the same way.
Workaround
Pass values into a process Claude starts via environment variables, rather than relying on any file
under %APPDATA%. Do not ask Claude to verify anything about files in that subtree.