Windows: Claude Code reads a stale snapshot of %APPDATA%, silently returning wrong file contents

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 4, 2026

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

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

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

  1. Start a Claude Code session on a Windows project.
  2. In a separate terminal, outside Claude, write a file under %APPDATA% — e.g.

dotnet user-secrets set ..., or simply create %APPDATA%\fs-test.txt.

  1. Ask Claude to read it:

Get-Item "$env:APPDATA\fs-test.txt" | Select-Object FullName, LastWriteTime, Length

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

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

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

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

  1. dangerouslyDisableSandbox does not escape it, which makes it present as a filesystem

problem rather than a sandbox policy, and sends debugging in the wrong direction.

  1. Breaks the documented workflow for .NET local development. dotnet user-secrets is

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.

View original on GitHub ↗