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 <noreply@anthropic.com>
This commit is contained in:
jacob-wang 2026-04-20 20:41:23 +08:00
parent d0782c4c4d
commit 1d430ca471
1 changed files with 8 additions and 2 deletions

View File

@ -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;
}
}