[BUG] Cowork (cloud) re-serves stale local-file content within a session: after a file is staged once, re-staging the same path returns the OLD bytes while reporting the file's NEW size/mtime (false all-clear)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Re-staging a file path that was already staged earlier in the same Claude Desktop agent-mode
(Cowork) session returns the content the file had at first stage, even after the file has
changed on the device. The stale copy is complete and valid — it decodes, parses and
terminates correctly — so nothing in the session looks wrong.
Worse, the staging tool reports the device's current metadata (byte count and mtime)
while delivering the stale bytes. A caller that defensively compares reported size against
expected size sees agreement and proceeds on old content.
We reproduced this deterministically with a six-probe corpus and hash-level ground truth
(details below). Measured conclusions:
- The cache key is path-only. Invalidation ignores size, mtime and content:
- file grew 236 B → 1270 B: still served the 236 B version;
- file shrank 341 B → 100 B: still served the 341 B version;
- file changed content at an identical 379 B length: still served the old content;
- device mtimes were fresh and were reported as fresh, yet bytes were stale.
- Sticky: three re-stages in-session, plus a fourth ~14 minutes later — stale every time.
No retry recovers the file.
- Scope: only paths staged earlier in the same session. A newly created path staged
for the first time is correct, and a device-native read (executing on the device instead of
staging) returns the current file. So the device is fine and the FUSE mount is fine — the
staleness is confined to the staging layer.
Real-world impact, twice, before we understood it:
- A code review nearly rejected a correct patch: the reviewing session was served a stale
dashboard_gen.py (101,286 B, an older complete version) while the tool reported the
device's 106,552 B. It "read" the file, found the fix missing, and almost bounced it.
- A session was served stale
STATE.md+DECISIONS.mdhandoff files and began planning
from a superseded project state.
What Should Happen?
Re-staging a path that has changed on the device should deliver the current file.
Failing that, the two acceptable fallbacks — in order of preference:
- Attach a validator to the cache entry (size + mtime, or a content hash) and revalidate
on re-stage. Size+mtime alone fixes the two size-changing cases; the same-size content
change additionally needs a content hash or an explicit invalidate-on-re-stage.
- At minimum, never report fresh metadata over stale bytes. If a cached copy is served,
the reported byte count/mtime must describe what was delivered, not what is on the
device. Today's behaviour destroys the only signal a client could act on — as it stands,
there is no in-session check that can detect the staleness.
Error Messages/Logs
**None — and that is the core of the report.** There is no error, no warning, no exception.
The stale file is complete, valid UTF-8, correctly terminated and parses normally. The only
observable is a hash comparison against the device, which requires an out-of-band channel.
Representative captured pair (probe P1):
device (ground truth, after change): 1270 bytes md5 ee27ce3caa4464cf974034aedf38f82b MARKER: P1-grow-v2-34031eed
staging tool REPORTED: 1270 bytes (+ the device's fresh mtime)
bytes actually DELIVERED: 236 bytes md5 e2c62e5a0e349e62610fe00148eab247 MARKER: P1-grow-v1-9bf861ce
The same-size probe (P3) is the sharpest case — reported, delivered and device sizes all
agree at 379 bytes, while the content is a version behind:
device (after change): 379 bytes md5 c86d1d2f7bc9301bec007b7d65271e80 MARKER: P3-samesize-v2-b69a42a5
delivered: 379 bytes md5 046fee935460aebe182a326151e80378 MARKER: P3-samesize-v1-c0939a6e
Steps to Reproduce
Requires two seats: one with native device filesystem access (mutator) and one
cloud/staging agent session (observer). A mount-backed session cannot reproduce this
and will read everything live — verify your observer actually stages before trusting a clean
result (stage a path, change it on the device, re-read without re-staging: frozen content
means you stage).
Steps 1–4 must happen in one continuous observer session; if it ends in between, the
cache dies with it and everything reads fresh.
- Device seat: create a small text file, e.g.
probe.md, whose body contains a unique
marker line so any copy identifies itself:
````
VERSION: v1
MARKER: probe-v1-9bf861ce
Record its size and md5.
- Observer (staging session): stage/read
probe.md. It returns v1 — expected; this
caches the path. Keep this session open.
- Device seat: change
probe.mdin place —VERSION: v2, a new marker. Record the new
size and md5. (Do this three ways across three files to characterise the key: one that
grows, one that shrinks, and one whose byte length is unchanged while content differs.)
- Same observer session: re-stage the same paths and compare, for each file:
- the byte count/metadata the tool reports, versus
- the bytes actually delivered (length, md5, marker line).
Observed: all three deliver the v1 marker; reported metadata matches the device's new
values. The same-size file is delivered stale with reported size == delivered size.
- Re-stage the grown file two or three more times, and again after ~15 minutes — still
stale, no self-heal.
- Create a new file that has never been staged and stage it — correct. Read the grown
file via a device-native execution path instead of staging — correct.
Minimal discriminator if you only run one probe: step 3's same-byte-length content change.
It is what proves the key excludes content, and it is the case no client-side size check can
catch.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude Desktop: 1.22209.3.0 (Claude_1.22209.3.0_x64__pzs8sxrjxfjjc); CLAUDE_AGENT_SDK_VERSION: 0.3.215; CLAUDE_CODE_ENTRYPOINT: claude-desktop
Platform
Other
Operating System
Windows
Terminal/Shell
Other
Additional Information
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗