anthropics / anthropics/claude-code

[BUG] Cowork: device_commit_files reports success on overwrites but the on-disk content lags exactly one commit behind (silent stale write, fresh mtime)

未关闭
#93,482 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
area:cowork bug data-loss has repro platform:windows
主要语言
Python
星标
145k
派生
23.1k
PR 合并指标
PR 指标待抓取

描述

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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?

## Summary

When a cloud Cowork session writes back to a file that **already exists** on the linked device, `device_commit_files` returns `{"written":[path],"rejected":[]}`, the file's modification time advances to the moment of the call, and **the content on disk is the payload from the previous commit**. Committing the identical payload a second time lands it.

Creating a **new** file is unaffected and correct every time. Only overwrites are affected.

This is a silent data-integrity failure. The session has no signal that anything went wrong, and the file it just "wrote" looks freshly updated to any human or tool inspecting it, because the timestamp is current while the bytes are stale.

## Impact

This is worse than a loud failure for two reasons.

1. **The success response is indistinguishable from a real write.** An agent that follows the obvious contract, commit and move on, will report work as saved that was not saved.
2. **The timestamp lies in the same direction.** A stale file carries the new write's mtime, so ordinary "has this been updated?" checks, sync tools, and human inspection all agree with the false success.

For anyone using a Cowork workspace with recurring update routines, the exposed operations are exactly the common ones: appending to a running log, updating a status line, bumping a version, editing a spec. Every one of those is an overwrite. The drift is invisible until someone reads the file much later.

## Workaround

Commit the same payload twice, then stage the file back and grep the content for the intended change. Byte count is a weak check and the timestamp is no check at all. Where possible, do write-heavy work in Claude Code instead, which writes to disk directly and does not use this path. (Confirmed clean by test on the same machine: new file, two Write-tool overwrites, and one Edit-tool in-place edit, each verified from a separate PowerShell process, all four exact with no lag.)

## Suggested area to look at

The off-by-one shape suggests something in the commit path is buffering or staging the payload and swapping in the previous one for the overwrite case, since the create case is correct. The mtime being updated from the current call while the bytes come from the prior call points at the metadata write and the content write reading from different sources.

### What Should Happen?

After `device_commit_files` returns `written` with no rejections, the file on disk should contain the committed payload. If the write cannot be completed, the call should report the path in `rejected` rather than returning success.

### Error Messages/Logs

```shell

```

### Steps to Reproduce

## Reproduction

Minimal repro, run against a plain local folder (`C:\Users\\Downloads`, **not** OneDrive-backed):

| Step | Action | Committed payload | Commit result | On disk immediately after |
|---|---|---|---|---|
| 1 | `device_commit_files` (new file) | `VERSION-A…` (43 bytes) | `written`, no rejections | **43 bytes, VERSION-A** ✅ |
| 2 | `device_commit_files` (overwrite) | `VERSION-B…` (82 bytes) | `written`, no rejections | **43 bytes, VERSION-A** ❌ (mtime advanced) |
| 3 | `device_commit_files` (same payload again) | `VERSION-B…` (82 bytes) | `written`, no rejections | **82 bytes, VERSION-B** ✅ |
| 4 | `device_commit_files` (overwrite) | `VERSION-C…` (89 bytes) | `written`, no rejections | **82 bytes, VERSION-B** ❌ (mtime advanced) |
| 5 | Wait 45 s, re-read, **no** intervening commit | — | — | **82 bytes, VERSION-B** ❌ |

Payload lengths were chosen to differ, so byte count alone distinguishes the revisions without inspecting content. Content was checked as well via `device_stage_files` and matched the byte count in every case.

## What this rules out

- **Not a read cache.** Step 5 waited 45 seconds with no intervening commit and the stale content persisted. `device_list_dir` and `device_stage_files` agreed with each other at every step.
- **Not OneDrive.** First observed on files under a OneDrive-synced folder, then reproduced identically in `C:\Users\\Downloads`, outside OneDrive entirely.
- **Not KB5124008.** That update broke the Hyper-V Plan9 shares used by `device_bash` on this machine (see #92984). The local sandbox shell was completely non-functional throughout this testing while the file bridge kept working, so the two are on different code paths.
- **Not `force`.** Behavior is identical with and without `force: true`, and with and without `expectedMtimeMs`.

## Observed elsewhere in the same session

Reproduced five separate times across four different files before it was isolated:

- two markdown files under a OneDrive-synced connected folder (~8 KB and ~65 KB), twice each
- a `.ps1` script file in the same folder
- the `Downloads` test file above

In every case the pattern was the same: first commit reports success and leaves the prior revision, second identical commit lands the new content.

### Claude Model

Opus

### Is this a regression?

Yes, this worked in a previous version

### Last Working Version

_No response_

### Claude Code Version

Claude Desktop | 1.49585.0 |

### Platform

Anthropic API

### Operating System

Windows

### Terminal/Shell

Other

### Additional Information

## Environment

| | |
|---|---|
| Claude Desktop | 1.49585.0 |
| Platform | win32 x64 |
| Electron / Node | 44.2.0 / 24.20.0 |
| OS | Windows 11 25H2, OS Build 26200.9445 |
| Session type | Cowork **cloud** session linked to a desktop device |
| Model | claude-opus-5 |

## Related Issue

This may be related to: https://github.com/anthropics/claude-code/issues/83354

贡献指南

这个仓库没有索引到贡献指南

调研方向

Start at the device_commit_files entry point and compare its overwrite path with device_stage_files and device_list_dir using the Windows reproduction steps. Verify that each successful overwrite leaves the committed payload on disk immediately, and that failed writes are reported in rejected rather than written.

由索引模型根据 Issue 内容生成。

评估

技术栈
electron, node.js
领域
api, desktop
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
活跃
描述清晰度
基本清楚
新手友好度
48/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。