Skip to content

fix(oauth2): per-writer temp file for model-sync cache (concurrent-boot ENOENT)#54

Open
stephane-segning wants to merge 1 commit into
mainfrom
claude/nifty-rosalind-380250
Open

fix(oauth2): per-writer temp file for model-sync cache (concurrent-boot ENOENT)#54
stephane-segning wants to merge 1 commit into
mainfrom
claude/nifty-rosalind-380250

Conversation

@stephane-segning

Copy link
Copy Markdown
Contributor

What

Fixes a sync_failed … ENOENT … rename '<serverId>.json.tmp' -> '<serverId>.json' error seen in a real desktop-app log.

Root cause

The oauth2 model-sync cache writes atomically (write temp → rename onto the real path) but used a shared temp name ${filePath}.tmp. When several OpenCode instances boot at once — the desktop app restores every project window in parallel, each its own process — they all sync the same provider and race: process A's rename consumes the temp file process B just wrote, so B's rename fails with ENOENT.

Impact is cosmetic-but-noisy: the winning writer's atomic write still lands (cache never corrupts), but the loser logs ERROR sync_failed and falls back to a stale model list for that boot.

Fix

  • opencode-oauth2 saveServerState: per-writer temp name (pid + randomUUID()), with best-effort unlink on failure so a failed write never strands an orphan temp file. rename stays atomic → last-writer-wins on the final path.
  • opencode-models-info FileCacheStore.put: hardened the same way (it already used pid + Date.now(); added uuid for same-process/same-ms safety + orphan cleanup).

Tests / docs

  • Concurrent-write regression tests in both packages (25 parallel saves of the same key → all resolve, final file intact, no .tmp leftovers).
  • CHANGELOG.md Unreleased entry.
  • docs/troubleshooting.md: a symptom-keyed entry for the ENOENT rename error.

Pre-push gate (build + typecheck + test + lint + format:check) green.

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request resolves a file-renaming race condition (ENOENT error) that occurs when multiple OpenCode instances boot concurrently and attempt to write to the same cache file. By updating both the opencode-models-info and opencode-oauth2 cache stores to use unique temporary file names suffixed with the process ID and a random UUID, concurrent writers no longer collide. Additionally, error handling was added to clean up orphaned temporary files on failure, and concurrent test cases were introduced to verify the fix. There are no review comments to evaluate, and I have no additional feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

…ot ENOENT)

Several OpenCode instances booting at once (the desktop app restoring
every project window in parallel) all ran the oauth2 model sync for the
same provider and raced on a shared `<serverId>.json.tmp` temp file: one
writer's atomic rename consumed the temp file another was about to
rename, surfacing as `sync_failed … ENOENT … rename '*.json.tmp' ->
'*.json'`. Temp files are now per-writer (pid + uuid) and unlinked on
failure, so concurrent writers can't collide; rename stays atomic so
last-writer-wins on the final path.

Hardened the models-info FileCacheStore the same way (uuid + orphan
cleanup) and added concurrent-write regression tests to both packages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant