Snapshot capture failure (EPERM spawning git) fails the whole step despite the best-effort contract
维护者通常 1 天内回复
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 76/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- git, typescript
- 领域
- backend, testing-qa
调研方向
从 packages/core/src/snapshot.ts 开始,重点关注 Snapshot.capture 的错误处理程序和 packages/core/src/git.ts 中的 spawn 路径。使用一个抛出普通错误的 spawner 更新现有的 snapshot 单元测试,然后验证 capture 会记录警告、返回 undefined,并允许会话步骤继续。只有在类型化失败和抛出的缺陷都遵守 best-effort 契约时,此问题才算完成。
由索引模型根据 Issue 内容生成。
描述
Summary
On Windows, Snapshot.capture can fail with
EPERM: operation not permitted, uv_spawn 'C:\Program Files\Git\cmd\git.EXE'. The snapshot is
documented as best-effort and has an error handler, but this failure escapes it and fails the
whole step: the session ends the turn with an idle message and the user sees no error.
Environment
- opencode version: 2.0.26 (observed); source compared against 2.1.4
- OS: Windows 10.0.26300 (win32 x64)
- Terminal: unavailable:
TERM_PROGRAM/WT_SESSIONare not set (TERM=xterm-256color) - Shell:
powershell.exe(ComSpec=C:\WINDOWS\system32\cmd.exe) - Install/channel: latest
- Active plugins:
@cortexkit/[email protected]
Reproduction
Not reproduced deterministically — EPERM on spawn comes from the OS (Windows security
policy, antivirus/filesystem filter, or process-creation limits). The path is:
- Work in a git repository on Windows, keep the snapshot feature enabled.
- Trigger a step boundary at a moment when spawning
git.exeis refused for the server
process (EPERM). - The step fails; no tool call is interrupted, no message is produced.
A unit-level repro would be a spawner that throws from spawn() rather than failing with a
typed AppProcess.AppProcessError.
Expected Behavior
A snapshot failure is best-effort by contract (packages/core/src/snapshot.ts:45-47):
log a warning, return undefined, and let the step continue without a snapshot.
Actual Behavior
The error propagates out of Snapshot.capture → SessionStep.attempt → SessionRunner.drain
and ends the step:
timestamp=2026-10-23T11:49:10.570Z level=ERROR run=... message="Failed to drain Session"
cause="Error: EPERM: operation not permitted, uv_spawn 'C:\Program Files\Git\cmd\git.EXE'
at spawn (unknown)
at spawn (node:child_process:730:35)
at spawn (node:child_process:22:39)
at Cr (chunk-3kgnsp08.js:2:6060)
at AppProcess.run (chunk-bs2ghvry.js:21:1897)
at Git.tree.capture (chunk-b7pgr6s2.js:116:2552)
at Snapshot.capture (chunk-gfcrb6b.js:361:11390)
at SessionStep.attempt (chunk-gfcr6bw6.js:376:3409)
at SessionRunner.runStep (chunk-gfcr6bw6.js:376:2507)"
Three milliseconds later the session recorded an idle message (time_created 11:49:10.573Z)
and nothing else. There is no user-visible error and no indication that the turn ended
abnormally.
Additional Context
Why the handler does not catch it
packages/core/src/snapshot.ts:141:
}).pipe(
Effect.catch((cause) => Effect.logWarning("failed to capture snapshot", { cause }).pipe(Effect.as(undefined))),
)
In effect v4 Effect.catch is catchAll: it recovers typed failures (E) only. A spawn
error thrown by child_process arrives as a defect, so the handler never runs. The stack
above starts at spawn (node:child_process:730:35) and the error is a plain Error, not
AppProcess.AppProcessError — consistent with a defect.
2.1.4 does not cover it
snapshot.tsin 2.1.4 keeps the sameEffect.catch(...)handler at the same place.packages/core/src/git.ts:370-374(2.1.4) states explicitly: "Only a Git exit is retried,
never a failure to start Git."
Impact seen
The step ends silently in the middle of a user request; the conversation appears stuck until
the user sends another message.
Frequency in the log of one machine: 42 Failed to drain Session lines, 30 of them in a
single hour (2026-10-24T04:16Z, 30 consecutive entries within one minute — one session hitting
a local obstacle, not 30 independent cases). After upgrading to 2.1.4: 0 occurrences during
~35 minutes of observation. The sample after the upgrade is too short to call it fixed, and the
relevant code path is unchanged, so this stays open as an observation.
Platform scope
The defect is in the harness code path, not in the OS: any thrown error from spawning git
takes the same route out of the best-effort capture. EPERM is what a Windows endpoint
protection / filesystem filter produces; on Linux the same path is reachable through EACCES
from a noexec mount, SELinux/AppArmor denials, or cgroup limits. So the fix matters on every
platform, while the trigger frequency is far higher on Windows. All measurements below are from
Windows.
Suggested fix direction
Catch defects (Effect.catchCause / Effect.catchAllCause, or Effect.orElseSucceed)
around the snapshot body so the documented best-effort contract holds for thrown spawn
failures too, and surface the failure as a warning in the session log.
- 主要语言
- TypeScript
- 星标
- 221k
- 派生
- 29.6k
- 平均合并
- 4 小时 35 分钟
- 30 天内合并 PR
- 521
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
anomalyco/opencode 的其他 Issue
-
triaging
难度 2/5 1-3 小时 新手友好度 65/100
anomalyco/opencode#58821 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 85/100
anomalyco/opencode#58774 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
anomalyco/opencode#58725 · 1 条评论 ·
维护者通常 1 天内回复
-
tui: PHP code blocks without `<?php` are not syntax highlighted可能已有人在做 @SwastikTripathi 于 1 天前认领。 未关闭reproduced
难度 2/5 1-3 小时 新手友好度 76/100
anomalyco/opencode#58664 · 2 条评论 ·
维护者通常 1 天内回复
-
patch: moving an executable script removes its executable bit可能已有人在做 @chenyb999-zhcn 于 1 天前认领。 未关闭reproduced
难度 2/5 1-3 小时 新手友好度 78/100
anomalyco/opencode#58651 · 2 条评论 ·
维护者通常 1 天内回复
查看 anomalyco/opencode 的全部 Issue
相似的 Issue
-
a10y a10y-audit ai-driven-qa claude
难度 2/5 1-3 小时 新手友好度 86/100
linagora/twake-directory-manager#219 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复
-
type: bug
难度 2/5 1-3 小时 新手友好度 79/100
维护者通常 1 天内回复
-
0️⃣ phase/new
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
Pulse v7: buildPreferencesFromTelos() bypasses telosSectionOrFile(), renders empty on unified-TELOS installs可能已有人在做 @zephyr91 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 75/100
danielmiessler/LifeOS#2393 ·
维护者通常 4 天内回复