{"record":{"id":"7f582a17916b4a41","repo":"gastownhall/beads","slug":"writing-lock-info-w","errorCode":null,"errorMessage":"writing lock info: %w","messagePattern":"writing lock info: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/synclock.go","lineNumber":68,"sourceCode":"\t\t\treturn nil, fmt.Errorf(\"acquiring lock (blocking): %w\", err)\n\t\t}\n\t} else {\n\t\tif err := lockfile.FlockExclusiveNonBlocking(f); err != nil {\n\t\t\tif lockfile.IsLocked(err) || err == lockfile.ErrLockBusy {\n\t\t\t\tinfo := readContendedSyncLockInfo(infoPath)\n\t\t\t\t_ = f.Close()\n\t\t\t\treturn nil, &SyncLockHeldError{Info: info}\n\t\t\t}\n\t\t\t_ = f.Close()\n\t\t\treturn nil, fmt.Errorf(\"acquiring lock (non-blocking): %w\", err)\n\t\t}\n\t}\n\n\tmetadata, err := publishSyncLockInfo(f, infoPath)\n\tif err != nil {\n\t\t_ = lockfile.FlockUnlock(f)\n\t\t_ = f.Close()\n\t\treturn nil, fmt.Errorf(\"writing lock info: %w\", err)\n\t}\n\n\treturn &SyncLock{infoPath: infoPath, file: f, metadata: metadata}, nil\n}\n\n// Release releases the sync lock. The kernel-lock file is NOT removed — doing\n// so after unlocking creates a race where a blocked waiter acquires the old\n// inode while a new process creates a fresh file at the same path, splitting\n// lock identity. On Unix, inline owner metadata is truncated while still\n// holding the lock. On Windows, a separate advisory record is cleared while\n// still holding the authoritative guard.\nfunc (l *SyncLock) Release() error {\n\tif l == nil || l.file == nil {\n\t\treturn nil\n\t}\n\n\t// Clear or invalidate diagnostic metadata before releasing the authoritative\n\t// lock. Platform helpers preserve Unix errors and make Windows diagnostics","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/synclock.go#L50-L86","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before acquiring: ensure the beads dir is writable and has free space\ninfo, err := os.Stat(beadsDir)\nif err != nil || !info.IsDir() { return fmt.Errorf(\"bad beads dir: %w\", err) }\nprobe := filepath.Join(beadsDir, \".write-probe\")\nif err := os.WriteFile(probe, []byte(\"x\"), 0600); err != nil {\n    return fmt.Errorf(\"beads dir not writable: %w\", err)\n}\nos.Remove(probe)","typeGuard":null,"tryCatchPattern":"lock, err := linear.AcquireSyncLock(beadsDir, true)\nif err != nil && strings.Contains(err.Error(), \"writing lock info\") {\n    return fmt.Errorf(\"cannot persist lock metadata (check disk space/permissions): %w\", err)\n}","preventionTips":["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"],"tags":["file-lock","filesystem","disk-full","go"],"backgroundTag":"disk-full","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}