Skip to content

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

@michalszelagsonos

Description

@michalszelagsonos

Description

Starting with Gemini CLI 0.33.0, gemini --version (and any gemini command) triggers a concurrent startup race condition that produces:

Failed to save project registry to /home/runner/.gemini/projects.json: Error: ENOENT: no such file or directory, rename '/home/runner/.gemini/projects.json.tmp' -> '/home/runner/.gemini/projects.json'

Root Cause

In gemini.tsx, the CLI runs two cleanup functions concurrently:

await Promise.all([
    cleanupCheckpoints(),              // index 0
    cleanupToolOutputFiles(settings),  // index 1
]);

Both create separate StorageProjectRegistry instances targeting the same ~/.gemini/projects.json. When the file doesn't exist, both call ProjectRegistry.save() without locking (the proper-lockfile lock in getShortId() only engages after the initial save). Both write to the same projects.json.tmp path:

  1. A: writeFile('projects.json.tmp') → succeeds
  2. B: writeFile('projects.json.tmp') → overwrites A's file
  3. A: rename('projects.json.tmp', 'projects.json') → succeeds, tmp file gone
  4. B: rename('projects.json.tmp', 'projects.json')ENOENT — A already renamed it

Workaround

Pre-seed ~/.gemini/projects.json with {"projects":{}} before running any 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.

mkdir -p "${HOME}/.gemini"
if [[ ! -f "${HOME}/.gemini/projects.json" ]]; then
  echo '{"projects":{}}' > "${HOME}/.gemini/projects.json"
fi

Upstream Fix

The ideal fix would be in Gemini CLI itself — either share a single Storage/ProjectRegistry instance across both cleanup calls, or use a unique tmp file name (e.g., with PID or random suffix) in ProjectRegistry.save().

Environment

  • Gemini CLI version: 0.33.0
  • Runner: GitHub-hosted (Ubuntu 24.04)
  • Node.js: 20.20.0

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions