-
Notifications
You must be signed in to change notification settings - Fork 338
Description
Bug
A 0-byte .usage-cache.lock file permanently prevents usage data from being fetched or displayed. The HUD silently drops the usage section with no error or warning.
Root Cause
Race condition in usage-api.ts lock acquisition. The lock file is created in two steps:
fs.openSync(lockPath, 'wx')— creates file (0 bytes)fs.writeFileSync(fd, String(Date.now()))— writes timestamp
If the HUD process is killed between steps 1 and 2 (signal, OOM, terminal close, WSL2 lifecycle), a 0-byte lock file remains.
The stale-lock detector in tryAcquireCacheLock cannot recover from this:
// readLockTimestamp (line ~151)
const raw = fs.readFileSync(lockPath, 'utf8').trim(); // "" for 0-byte file
const parsed = Number.parseInt(raw, 10); // NaN
return Number.isFinite(parsed) ? parsed : null; // returns null
// tryAcquireCacheLock (line ~186)
const lockTimestamp = readLockTimestamp(lockPath);
if (lockTimestamp != null && Date.now() - lockTimestamp > CACHE_LOCK_STALE_MS) {
// ^^^ null != null is FALSE — stale check is skipped entirely
fs.unlinkSync(lockPath);
}
return 'busy'; // stuck foreverSince readLockTimestamp returns null for a corrupt/empty file, the lockTimestamp != null guard prevents the stale check from ever running. Every subsequent render sees "lock is busy" → waits 2s → gives up → no usage data.
Impact
- Usage percentages (5h, 7d) silently disappear from the HUD
- Plan label (
Max,Pro, etc.) may also disappear from the model bracket - No error message shown — user has no indication anything is wrong
- Persists across sessions until manually deleted
Environment
- Claude Code v2.1.42
- claude-hud v0.0.9
- Ubuntu 24.04 on WSL2
- Runtime: Bun 1.3.10
Suggested Fix
Treat a null timestamp (0-byte or corrupt lock file) as stale:
- if (lockTimestamp != null && Date.now() - lockTimestamp > CACHE_LOCK_STALE_MS) {
+ if (lockTimestamp == null || Date.now() - lockTimestamp > CACHE_LOCK_STALE_MS) {This way, a lock file with no valid timestamp is always cleaned up, matching the intent of the stale-lock mechanism.
Workaround
rm ~/.claude/plugins/claude-hud/.usage-cache.lock
rm ~/.claude/plugins/claude-hud/.usage-cache.jsonSteps to Reproduce
- Start a Claude Code session with claude-hud showing usage
- Simulate a kill during lock acquisition:
touch ~/.claude/plugins/claude-hud/.usage-cache.lock - Usage display disappears and never recovers