Skip to content

browse: parallel startup race on shared browse.json.tmp can fail bootstrap with ENOENT #299

@malikrohail

Description

@malikrohail

Description

When two /browse CLI invocations start at the same time for the same project and no browse server is already running, they can race during bootstrap and one startup fails.

I hit this while using the compiled browse binary and launching two commands in parallel. One command recovered; the other failed with:

[browse] Server connection lost. Restarting...
[browse] Server failed to start:
[browse] Failed to start: ENOENT: no such file or directory, rename '/Users/test/.gstack/browse.json.tmp' -> '/Users/test/.gstack/browse.json'

Steps to reproduce

  1. Ensure there is no active browse server and no existing state file for the current project.
  2. From the same working directory, launch two browse commands concurrently before the server is up.
  3. Example shape:
    • one command: "$B" snapshot -i
    • second command: "$B" text
  4. Observe that both clients try to bootstrap the same browse server.

Observed behavior

One startup path can fail with ENOENT while renaming the shared temp file to the final state file.

Expected behavior

Concurrent bootstrap should converge on a single healthy server for that project. The second client should wait, reuse the published state, or otherwise avoid failing during startup.

Suspected root cause

The CLI has no startup lock around ensureServer() / startServer(), so multiple clients can decide to start a server at once:

  • browse/src/cli.ts#L163-L240

The server writes state via a shared temp path and then renames it:

  • browse/src/server.ts#L347-L358

If two servers use the same .tmp path, one can rename it away before the other reaches renameSync.

Why this matters

The project explicitly emphasizes multi-session parallel work in the README (## 10-15 parallel sprints), which makes race-safe browse startup part of the core product promise rather than just an edge case.

Acceptance criteria

  • Two concurrent browse invocations in the same project no longer fail during bootstrap.
  • Startup uses either a lock or uniquely named temp files plus safe publish semantics.
  • A regression test covers parallel bootstrap.
  • Existing stale-state restart behavior still passes.

Additional context

I did not find an existing issue for this exact failure mode, and I also did not find an issue template in the repo.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions