Skip to content

browse: acquireServerLock catch block silently swallows non-EEXIST errors, masks real bugs as phantom lock contention #1084

Closed

Description

@punksterlabs

Observation

acquireServerLock() in browse/src/cli.ts (lines ~283–307 on current main) uses a bare catch {} on the fs.openSync(lockPath, 'wx') call. The same applies to the inner catch on the holder-PID read.

When ANY error other than EEXIST occurs (permissions, disk full, Bun fs regressions like the one fixed in #599 via cd66fc2f, future Windows quirks, etc.), execution falls through to:

  1. Inner readFileSync(lockPath) → throws (file doesn't exist, or unreadable)
  2. Inner catch → return null
  3. Caller sees null → prints "Another instance is starting the server, waiting..."
  4. 15s timeout → "Timed out waiting for another instance to start the server"

The user sees phantom lock contention that has nothing to do with locking.

Real-world consequence

I hit this today on Windows 11, Bun 1.3.10, on a gstack 0.13.2.0 install that happened to sit on commit 247fc3ba (PR #603) instead of cd66fc2f (PR #602 — the #599 fix). Both commits were tagged v0.13.2.0 but sit on divergent paths, and #603's merge appears to have carried the pre-fix cli.ts back in. main HEAD has the correct 'wx' code, but anyone installed at that snapshot gets the buggy version.

Spent ~30 minutes diagnosing through three agents before the root cause landed: same bug as #599, silently re-introduced, and the bare catch mask made it look like a lock problem rather than a Bun syscall failure. If the outer catch had been:

```ts
catch (err: any) {
if (err?.code === 'EEXIST') {
// existing holder-PID logic
} else {
console.error(`[browse] acquireServerLock: unexpected ${err?.code || ''} opening ${lockPath}: ${err?.message}`);
return null;
}
}
```

…the diagnostic would have taken 10 seconds.

Proposed Fix

Harden `acquireServerLock()` so only `EEXIST` goes down the holder-PID path. Everything else logs via `console.error` with the error code + path before falling back to `return null`. This:

  • Preserves current behavior for the common-path "lock is held" case
  • Surfaces real fs/syscall failures immediately (permissions, disk full, future Bun regressions)
  • Doesn't change the return type or any callers

Same treatment for the inner catch on the holder-PID read.

Environment

Why not file as a dup of #599

#599 was the specific bug (numeric `O_CREAT|O_EXCL|O_WRONLY` flags on Bun Windows). This issue is about the defensive-coding gap that made #599 and its look-alikes near-invisible to users. Independent of the root cause that motivated it.

Activity

  1. added a commit that references this issue on Apr 20, 2026
    1d430ca
  2. jbetala7 commented on May 26, 2026

    @jbetala7
    Contributor

    Opened PR #1725 with the lock-diagnostic hardening and focused regression coverage: #1725

  3. time-attack commented on Jul 15, 2026

    @time-attack
    Contributor

    @16francej — recommend closing this issue, because #1725 covers the same lock-error report and related races, while current code still masks non-EEXIST failures. It should close only after #1725 lands following its remaining check, with the original reproduction and reporter attribution retained.

  4. garrytan commented on Aug 15, 2026

    @garrytan
    Owner

    Fixed in fork-port wave 2: acquireServerLock no longer swallows non-EEXIST errors — real failures (EACCES, EROFS, ...) surface with the actual error instead of masquerading as phantom lock contention.

    Commit: d70e6586 fix(browse): lock acquisition reports real errors instead of phantom contention (#1084)
    Pinned by: browse/test/server-lock-errors.test.ts

    Ships in #2577 (v1.65.0.0).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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