gastownhall/beads · error
failed to create lock file: %w
Error message
failed to create lock file: %w
What it means
acquireBootstrapLock creates a bootstrap lock file (mode 0600) with os.OpenFile before trying to flock it. This error means the lock file itself could not be created/opened — the process never even got to the locking stage. It wraps the underlying OS error.
Source
Thrown at internal/storage/dolt/bootstrap.go:230
// Uses non-blocking flock with polling to respect the timeout deadline.
// Detects and cleans up stale lock files from crashed processes.
func acquireBootstrapLock(lockPath string, timeout time.Duration) (*os.File, error) {
// Check for stale lock file before attempting to acquire.
// If the lock file is very old, the holding process likely crashed
// without cleanup. Remove it so we can proceed.
if info, err := os.Stat(lockPath); err == nil {
age := time.Since(info.ModTime())
if age > staleLockAge {
fmt.Fprintf(os.Stderr, "Bootstrap: removing stale lock file (age: %s)\n", age.Round(time.Second))
_ = os.Remove(lockPath) // Best effort cleanup of lock file
}
}
// Create lock file
// #nosec G304 - controlled path
f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600)
if err != nil {
return nil, fmt.Errorf("failed to create lock file: %w", err)
}
// Try to acquire lock with non-blocking flock and polling.
deadline := time.Now().Add(timeout)
for {
err := lockfile.FlockExclusiveNonBlocking(f)
if err == nil {
// Lock acquired - update modification time for stale detection
return f, nil
}
if !lockfile.IsLocked(err) {
// Unexpected error (not contention)
_ = f.Close() // Best effort cleanup on error path
return nil, fmt.Errorf("failed to acquire bootstrap lock: %w", err)
}
if time.Now().After(deadline) {View on GitHub (pinned to 71377f2769)
Solutions
- Check that the lock file's parent directory exists and is writable (e.g. `ls -la .beads/` and `touch .beads/test` as the same user)
- Fix permissions: `chmod u+w .beads` or run as a user with write access to the repository
- Check for read-only filesystem or full disk (`mount`, `df -h`) and free space or remount read-write
Example fix
// before bd bootstrap // error: failed to create lock file: open .beads/bootstrap.lock: permission denied // after mkdir -p .beads && chmod u+w .beads bd bootstrap
Defensive patterns
Strategy: validation
Validate before calling
// ensure lock dir exists and is writable before bootstrap
info, err := os.Stat(beadsDir)
if err != nil || !info.IsDir() { os.MkdirAll(beadsDir, 0o755) }
if f, err := os.CreateTemp(beadsDir, ".writetest"); err != nil {
// directory not writable: fix permissions before bootstrap
} else { f.Close(); os.Remove(f.Name()) } Prevention
- Run bd from the repository root so relative .beads paths resolve
- Verify the user has write permission on .beads/ before automating bootstrap
- Check disk space and that the volume is mounted read-write
- Create .beads/ (via bd init) before calling bootstrap
When it happens
Trigger: os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600) fails: the `.beads` directory does not exist, the filesystem is read-only, permission denied on the lock path, disk full, or the path is invalid (e.g. wrong working directory).
Common situations: Running `bd bootstrap` in a directory where `.beads` has not been created or is not writable; running under a user without write permission to the repo; a read-only container/mount or full disk.
Related errors
- create beads directory: %w
- write metadata.json: %w
- create config.yaml: %w
- failed to create dolt directory: %w
- dolt path is not executable
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1fca13118162aff4.
Report an issue: GitHub.