gastownhall/beads · error
writing lock info: %w
Error message
writing lock info: %w
What it means
After acquiring the exclusive flock, AcquireSyncLock publishes diagnostic metadata (PID, start time) to the lock info file via publishSyncLockInfo. If that write fails, the kernel lock is released and this error is returned. The lock is NOT left held, so the sync did not start.
Source
Thrown at internal/linear/synclock.go:68
return nil, fmt.Errorf("acquiring lock (blocking): %w", err)
}
} else {
if err := lockfile.FlockExclusiveNonBlocking(f); err != nil {
if lockfile.IsLocked(err) || err == lockfile.ErrLockBusy {
info := readContendedSyncLockInfo(infoPath)
_ = f.Close()
return nil, &SyncLockHeldError{Info: info}
}
_ = f.Close()
return nil, fmt.Errorf("acquiring lock (non-blocking): %w", err)
}
}
metadata, err := publishSyncLockInfo(f, infoPath)
if err != nil {
_ = lockfile.FlockUnlock(f)
_ = f.Close()
return nil, fmt.Errorf("writing lock info: %w", err)
}
return &SyncLock{infoPath: infoPath, file: f, metadata: metadata}, nil
}
// Release releases the sync lock. The kernel-lock file is NOT removed — doing
// so after unlocking creates a race where a blocked waiter acquires the old
// inode while a new process creates a fresh file at the same path, splitting
// lock identity. On Unix, inline owner metadata is truncated while still
// holding the lock. On Windows, a separate advisory record is cleared while
// still holding the authoritative guard.
func (l *SyncLock) Release() error {
if l == nil || l.file == nil {
return nil
}
// Clear or invalidate diagnostic metadata before releasing the authoritative
// lock. Platform helpers preserve Unix errors and make Windows diagnosticsView on GitHub (pinned to 71377f2769)
Solutions
- Free disk space / raise quota on the volume holding the beads directory
- Verify the beads directory and lock files are writable by the current user
- Check nothing else deletes or chmods files inside the beads directory during sync
- Retry after fixing the filesystem condition — the flock was properly released on failure, so it is safe to retry
Defensive patterns
Strategy: validation
Validate before calling
// Before acquiring: ensure the beads dir is writable and has free space
info, err := os.Stat(beadsDir)
if err != nil || !info.IsDir() { return fmt.Errorf("bad beads dir: %w", err) }
probe := filepath.Join(beadsDir, ".write-probe")
if err := os.WriteFile(probe, []byte("x"), 0600); err != nil {
return fmt.Errorf("beads dir not writable: %w", err)
}
os.Remove(probe) Try / catch
lock, err := linear.AcquireSyncLock(beadsDir, true)
if err != nil && strings.Contains(err.Error(), "writing lock info") {
return fmt.Errorf("cannot persist lock metadata (check disk space/permissions): %w", err)
} Prevention
- Monitor free disk space on the volume hosting the beads directory
- Keep beads directories off read-only or network mounts
- Don't run cleanup jobs that touch lock files inside .beads during sync
- Retry after fixing filesystem conditions — the lock is released cleanly on this error path
When it happens
Trigger: Calling AcquireSyncLock when publishSyncLockInfo → writeLockInfo fails to truncate/seek/write the lock-info file — typically disk full, read-only filesystem, or the info path becoming unwritable.
Common situations: Disk-quota exhaustion on the volume holding the beads directory; beads dir on a read-only mount; another tool deleting or chmod-ing the lock metadata path between open and write; Windows handle contention on the info file.
Related errors
- failed to write temp file: %w
- failed to write interactions log entry: %w
- clearing lock metadata: %w
- truncating lock file: %w
- proxy.ForceStopUnverified: acquire %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7f582a17916b4a41.
Report an issue: GitHub.