Skip to content

fix: pre-seed ~/.gemini/projects.json to prevent ENOENT from concurrent ProjectRegistry saves#483

Closed
michalszelagsonos wants to merge 2 commits intogoogle-github-actions:mainfrom
michalszelagsonos:fix/gemini-home-dir-enoent
Closed

fix: pre-seed ~/.gemini/projects.json to prevent ENOENT from concurrent ProjectRegistry saves#483
michalszelagsonos wants to merge 2 commits intogoogle-github-actions:mainfrom
michalszelagsonos:fix/gemini-home-dir-enoent

Conversation

@michalszelagsonos
Copy link

@michalszelagsonos michalszelagsonos commented Mar 15, 2026

Summary

  • Fixes ENOENT error on Gemini CLI 0.33.0: concurrent ProjectRegistry saves race on projects.json.tmp #482
  • Workaround for upstream bug: google-gemini/gemini-cli#22583
  • Gemini CLI 0.33.0+ runs cleanupCheckpoints() and cleanupToolOutputFiles() concurrently via Promise.all during startup (including gemini --version). Both create separate ProjectRegistry instances that target the same ~/.gemini/projects.json file.
  • When the registry file doesn't exist, both call save() without locking (the proper-lockfile lock in getShortId() only engages after the initial save). Both write to the same projects.json.tmp path. One rename() succeeds, the other gets ENOENT because the tmp file was already renamed away by the first.
  • Workaround: Create ~/.gemini/ and pre-seed projects.json with valid empty data ({"projects":{}}) before the first gemini command. This causes both concurrent callers to skip the unguarded initial save() and go straight to proper-lockfile's lock(), which properly serializes access. This workaround can be removed once the upstream fix lands.

Test plan

  • Run the GitHub Action workflow with Gemini CLI 0.33.0+
  • Confirm the Failed to save project registry ENOENT error no longer appears
  • Verify the rest of the action (authentication, CLI execution, output) works normally

Gemini CLI 0.33.0 writes a user-level project registry at
~/.gemini/projects.json during cleanup. The atomic write fails with
ENOENT if ~/.gemini/ doesn't exist. Add mkdir -p before the first
gemini command to ensure the directory is present.
… CLI

The previous mkdir-only fix was insufficient. Gemini CLI 0.33.0 runs
cleanupCheckpoints() and cleanupToolOutputFiles() concurrently via
Promise.all. Both initialize a ProjectRegistry that writes to the same
projects.json.tmp file. When the registry file doesn't exist, both call
save() without locking, causing a race where one rename succeeds and the
other gets ENOENT because the tmp file was already renamed away.

Pre-seeding projects.json with valid empty data causes both concurrent
callers to skip the unguarded initial save and go straight to
proper-lockfile's lock(), which properly serializes access.
@michalszelagsonos michalszelagsonos changed the title fix: create ~/.gemini directory before CLI invocation to prevent ENOENT fix: pre-seed ~/.gemini/projects.json to prevent ENOENT from concurrent ProjectRegistry saves Mar 15, 2026
@michalszelagsonos michalszelagsonos deleted the fix/gemini-home-dir-enoent branch March 16, 2026 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

ENOENT error on Gemini CLI 0.33.0: concurrent ProjectRegistry saves race on projects.json.tmp

1 participant