gastownhall/beads · error
acquiring lock (non-blocking): %w
Error message
acquiring lock (non-blocking): %w
What it means
AcquireSyncLock with wait=false attempts a non-blocking exclusive flock; a contention result is converted to SyncLockHeldError, but any other flock failure is wrapped as this error. It means the non-blocking acquire failed for a reason other than the lock simply being held.
Source
Thrown at internal/linear/synclock.go:60
f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600) // #nosec G304 -- lockPath is constrained to the beads directory.
if err != nil {
return nil, fmt.Errorf("opening lock file: %w", err)
}
if wait {
if err := lockfile.FlockExclusiveBlocking(f); err != nil {
_ = f.Close()
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 whileView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error to find the underlying OS failure and fix it (permissions, filesystem support)
- Delete a stale/corrupt .linear-sync.lock file (only if no sync is running) and retry
- Move the beads directory to a local filesystem if flock is unsupported
- If the intent was to skip when another sync runs, note that contention is reported as SyncLockHeldError instead — handle that type separately
Example fix
// before: treating all errors the same
lock, err := linear.AcquireSyncLock(beadsDir, false)
if err != nil { return err }
// after: distinguish contention from real failure
lock, err := linear.AcquireSyncLock(beadsDir, false)
var held *linear.SyncLockHeldError
if errors.As(err, &held) {
return nil // another sync running; skip
}
if err != nil { return fmt.Errorf("lock failure: %w", err) } Defensive patterns
Strategy: type-guard
Type guard
func isSyncLockHeld(err error) bool {
var held *linear.SyncLockHeldError
return errors.As(err, &held)
}
// Usage: if !isSyncLockHeld(err) { return err } // real failure, not contention Try / catch
lock, err := linear.AcquireSyncLock(beadsDir, false)
if err != nil {
if isSyncLockHeld(err) {
return nil // expected contention; skip run
}
return fmt.Errorf("non-blocking lock acquire failed: %w", err)
}
defer lock.Release() Prevention
- Always distinguish SyncLockHeldError (expected contention) from generic errors using errors.As
- Don't chmod or delete .linear-sync.lock while syncs may run
- Run on filesystems with reliable flock support
- Log the wrapped cause for unexpected non-contention failures
When it happens
Trigger: Calling AcquireSyncLock(beadsDir, false) when lockfile.FlockExclusiveNonBlocking returns an error that is neither lockfile.IsLocked(err) nor ErrLockBusy — e.g. I/O errors, EBADF, or platform flock anomalies.
Common situations: Corrupted or unreadable lock file; filesystem not supporting flock; running on a platform where the lock helper hits an unexpected OS error; unusual permission changes on .linear-sync.lock after creation.
Related errors
- acquiring lock (blocking): %w
- ErrLockHeld
- lock busy: held by another process
- lock already held by another process
- server: ExternalDoltServer.Start: server already started
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8ea0780bb3b1b9ba.
Report an issue: GitHub.