Whole-config rejection without last-good fallback kills all running sessions when a concurrent writer leaves a transient partial state in opencode.jsonc
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 48/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- json, typescript
- 領域
- backend
調査の方向性
Start with packages/core/src/config.ts, especially parseInfo and loadFile, and compare the well-known source fallback policy described there. Then inspect packages/util/src/fs-util.ts and the atomic temp-file rename pattern in packages/core/src/git.ts. Define done as ensuring transient partial writes cannot make active sessions lose the last valid configuration; the issue describes atomic writes or last-good fallback as acceptable approaches.
索引モデルが issue の本文から書いたものです。
説明
Description
When any concurrent writer leaves a transient partial state in the live global config file (~/.config/opencode/opencode.jsonc), a reloading opencode process fails to parse it and rejects the WHOLE configuration document - there is no fallback to the last-good configuration. The provider catalog then loses every model, and each running session dies at its next step with SessionRunnerModel.ModelUnavailableError ("Failed to drain Session"). Observed live on v2.2.5 with several concurrent opencode serve --stdio / ACP clients: 11 "rejected malformed JSON or JSONC document" normalization warnings, each followed within seconds by session-drain failures across three server processes.
Two contributing factors verified at tag v2.2.5:
- Whole-document rejection without last-good fallback:
packages/core/src/config.ts(parseInfo/loadFile) drops the entry entirely when JSONC parsing fails. The codebase already follows the opposite policy for well-known sources - a failed refresh keeps the last resolved config "so remote providers and allowlists do not disappear" (config.ts, comment above the wellknown load path) - so extending that resilience to parse failures of the user's own config matches existing intent. - In-place write of the live config:
packages/core/src/config.tsline 482 persists viafs.writeWithDirs(filepath, ...), which resolves to a directfs.writeFileString(path, content)without a temp-file + rename swap (packages/util/src/fs-util.ts,writeWithDirs). The codebase already uses an atomic temp+rename pattern elsewhere (for examplepackages/core/src/git.tsaround line 967).
Reproduction notes: hammering PATCH /api/experimental/config 1200x against one server while another watched the same directory did NOT reproduce a partial read through opencode's own write path - its synchronous write completes before the watcher's next tick can observe intermediate bytes. However, any slower concurrent writer (editor autosave, scripts, plugin installs touching large configs) leaves the truncated-to-flushed window open long enough for readers to hit it, which matches how the live incidents occurred outside of controlled testing.
Expected behavior: readers of the live config never lose the entire configuration because of one transiently inconsistent state - either writes go through an atomic swap so partial states cannot be observed at all, or a parse failure falls back to the last-known-good document instead of dropping everything.
Plugins
none
OpenCode version
v2.2.5
Steps to reproduce
- Run two opencode server processes that watch the same global config directory.
- While sessions are active on both, have any third party rewrite the global config non-atomically and slowly enough that a reload lands inside the truncated-to-flushed window (editor-style save or chunked script write over a multi-kilobyte config).
- Observe "configuration normalization diagnostic ... rejected malformed JSON or JSONC document" in the log immediately followed by "Failed to drain Session" errors with
ModelUnavailableErroron all active sessions - no manual intervention recovers them until the file parses again.
Screenshot
n/a
Operating System
Ubuntu 24.04.5 LTS
Terminal
not applicable (ACP client)
Related Issues
- https://github.com/anomalyco/opencode/issues/16450 - plugin config files deleted when multiple opencode instances run concurrently; different mechanism (concurrent
bun installdeleting files), closed without a fix. This report covers whole-document rejection on partial reads, which kills running sessions instead of losing files.
- 主要言語
- TypeScript
- スター
- 225k
- フォーク
- 30.4k
- 平均マージ
- 4時間 16分
- マージ済み PR(30日)
- 528
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
anomalyco/opencode のほかの issue
-
reproduced
難易度 2/5 1〜3時間 初心者へのやさしさ 61/100
anomalyco/opencode#62873 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
anomalyco/opencode#62822 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
anomalyco/opencode#62601 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
reproduced
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
anomalyco/opencode#62516 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
anomalyco/opencode#62374 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
anomalyco/opencode の issue をすべて見る
似ている issue
-
code-quality good-first-issue
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
OpenRailAssociation/netzgrafik-editor-frontend#1481 ·
メンテナーはふだん 1 日以内に返信
-
🙌 icon request
難易度 2/5 1〜3時間 初心者へのやさしさ 63/100
lucide-icons/lucide#5183 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 81/100
cloudflare/capnweb#293 ·
メンテナーはふだん 2 日以内に返信
-
bug implicit-state
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
-
area:models enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信