gastownhall/beads · error
truncating lock file: %w
Error message
truncating lock file: %w
What it means
writeLockInfo refreshes the lock file contents with owner metadata, starting by truncating the file to zero. This error wraps a Truncate(0) failure on the held lock file, and propagates up through publishSyncLockInfo into AcquireSyncLock's "writing lock info" error.
Source
Thrown at internal/linear/synclock.go:121
return metadataErr
}
// SyncLockHeldError is returned when the lock is held by another process.
type SyncLockHeldError struct {
Info *SyncLockInfo
}
func (e *SyncLockHeldError) Error() string {
if e.Info != nil {
return fmt.Sprintf("another bd linear sync is already running (PID %d, started %s)",
e.Info.PID, e.Info.Started.Format(time.RFC3339))
}
return "another bd linear sync is already running"
}
func writeLockInfo(f *os.File) error {
if err := f.Truncate(0); err != nil {
return fmt.Errorf("truncating lock file: %w", err)
}
if _, err := f.Seek(0, 0); err != nil {
return err
}
info := fmt.Sprintf("pid=%d\nstarted=%s\n", os.Getpid(), time.Now().UTC().Format(time.RFC3339))
_, err := f.WriteString(info)
return err
}
func readLockInfo(path string) *SyncLockInfo {
data, err := os.ReadFile(path) // #nosec G304 -- path is constructed from beadsDir, not user input
if err != nil {
return nil
}
return parseLockInfo(string(data))
}
func parseLockInfo(content string) *SyncLockInfo {View on GitHub (pinned to 71377f2769)
Solutions
- Check and free disk space on the filesystem holding the beads directory
- Ensure no external tooling deletes/recreates files in the beads directory during sync
- Verify the beads directory is on a local filesystem with reliable file operations
- Retry the sync once the filesystem condition is fixed; the lock is released cleanly on this failure path
Defensive patterns
Strategy: validation
Validate before calling
// Check usable space before starting sync (statfs on Go 1.21+)
var st syscall.Statfs_t
if err := syscall.Statfs(beadsDir, &st); err == nil {
freeBytes := int64(st.Bavail) * int64(st.Bsize)
if freeBytes < 1<<20 { return fmt.Errorf("less than 1MB free on %s", beadsDir) }
} Try / catch
lock, err := linear.AcquireSyncLock(beadsDir, true)
if err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
return fmt.Errorf("lock file I/O problem at %s: %w", pe.Path, err)
}
return err
} Prevention
- Alert on low disk space for volumes hosting beads directories
- Do not delete/replace the lock file while a holder has it open
- Avoid NFS for the beads directory (attribute-cache inconsistencies)
- Fix filesystem conditions and retry; the failed acquisition releases the flock cleanly
When it happens
Trigger: AcquireSyncLock succeeds on the flock but the subsequent f.Truncate(0) on the open lock file fails — typically I/O errors, disk full (with some filesystems), or the underlying file being replaced/deleted while held.
Common situations: Volume running out of space; lock file removed and recreated by another tool between open and truncate; NFS attribute-cache inconsistency; read-only remount after lock acquisition.
Related errors
- failed to write temp file: %w
- failed to write interactions log entry: %w
- failed to read backup state: %w
- failed to sync temp file: %w
- failed to write issue %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d78a8e6b56db131e.
Report an issue: GitHub.