From 1d430ca4718f73929da73708cad1f498a6f86acd Mon Sep 17 00:00:00 2001 From: jacob-wang Date: Mon, 20 Apr 2026 20:41:23 +0800 Subject: [PATCH] fix: surface non-EEXIST errors in acquireServerLock instead of masking them The bare `catch {}` on `fs.openSync(lockPath, 'wx')` silently swallowed all errors other than EEXIST (permissions, disk full, Bun regressions), making real fs failures look like phantom lock contention. Now only EEXIST takes the holder-PID path; everything else logs via console.error with error code and message before returning null. Inner catch on holder-PID read gets the same treatment. Fixes #1084 Co-Authored-By: Claude Opus 4.7 --- browse/src/cli.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/browse/src/cli.ts b/browse/src/cli.ts index 30ab7555b..a8ab8e24e 100644 --- a/browse/src/cli.ts +++ b/browse/src/cli.ts @@ -289,7 +289,12 @@ function acquireServerLock(): (() => void) | null { fs.writeSync(fd, `${process.pid}\n`); fs.closeSync(fd); return () => { safeUnlink(lockPath); }; - } catch { + } catch (err: any) { + if (err?.code !== 'EEXIST') { + // Unexpected error — surface it rather than masking as phantom lock contention + console.error(`[browse] acquireServerLock: unexpected ${err?.code || ''} opening ${lockPath}: ${err?.message}`); + return null; + } // Lock already held — check if the holder is still alive try { const holderPid = parseInt(fs.readFileSync(lockPath, 'utf8').trim(), 10); @@ -299,7 +304,8 @@ function acquireServerLock(): (() => void) | null { // Stale lock — remove and retry fs.unlinkSync(lockPath); return acquireServerLock(); - } catch { + } catch (err: any) { + console.error(`[browse] acquireServerLock: stale-lock read failed: ${err?.message}`); return null; } }