Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Snapshot capture failure (EPERM spawning git) fails the whole step despite the best-effort contract

未关闭 适合新手
#58,685 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@Dopetaiga 已经在做这个了。

开始于 2026年10月24日。

  • #58722 来自 @Dopetaiga —— 未关闭

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
76/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
git, typescript

调研方向

从 packages/core/src/snapshot.ts 开始,重点关注 Snapshot.capture 的错误处理程序和 packages/core/src/git.ts 中的 spawn 路径。使用一个抛出普通错误的 spawner 更新现有的 snapshot 单元测试,然后验证 capture 会记录警告、返回 undefined,并允许会话步骤继续。只有在类型化失败和抛出的缺陷都遵守 best-effort 契约时,此问题才算完成。

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

描述

reproduced

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_SESSION are 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:

  1. Work in a git repository on Windows, keep the snapshot feature enabled.
  2. Trigger a step boundary at a moment when spawning git.exe is refused for the server
    process (EPERM).
  3. 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.ts in 2.1.4 keeps the same Effect.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

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

anomalyco/opencode 的其他 Issue

查看 anomalyco/opencode 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

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