twpayne/chezmoi · critical

open %s: failed to acquire lock: %w

Error message

open %s: failed to acquire lock: %w

What it means

open in boltpersistentstate.go:236 opens the bbolt state database with flock-based locking. On syscall.EINVAL it assumes flock(2) failed and wraps the error as "open %s: failed to acquire lock", indicating the lock could not be acquired on the state database file.

Source

Thrown at internal/chezmoi/boltpersistentstate.go:236

		if err != nil {
			return err
		}
		return b.Put(key, value)
	})
}

// open opens b's database if it is not already open, creating it if needed.
func (b *BoltPersistentState) open() error {
	if b.db != nil {
		return nil
	}
	if err := MkdirAll(b.system, b.path.Dir(), fs.ModePerm); err != nil {
		return err
	}
	switch db, err := bbolt.Open(b.path.String(), 0o600, &b.options); {
	case errors.Is(err, syscall.EINVAL):
		// Assume that any EINVAL error is because flock(2) failed.
		return fmt.Errorf("open %s: failed to acquire lock: %w", b.path, err)
	case err != nil:
		return fmt.Errorf("open %s: %w", b.path, err)
	default:
		b.empty = false
		b.db = db
		return nil
	}
}

View on GitHub (pinned to f901167e46)

Solutions

  1. Move the chezmoi state directory to a local filesystem (set CHEZMOI state dir / use default ~/.config/chezmoi).
  2. If on NFS/SMB, remount with local locking enabled or switch to local storage.
  3. Check for stale locks/other chezmoi processes holding the file; stop them and retry.
  4. Verify kernel/filesystem support for flock on the mount (e.g. avoid tmpfs quirks in restricted containers).

Example fix

# before: state on NFS mount
export CHEZMOI_HOME=/mnt/nfs/chezmoi
# after
unset CHEZMOI_HOME  # use default local ~/.config/chezmoi
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure state dir is on a filesystem supporting flock
st, err := os.Stat(stateDir)
if err != nil { return err }
// e.g. reject known network mounts
if strings.HasPrefix(mntType(stateDir), "nfs") {
    return fmt.Errorf("state dir must be on a local filesystem")
}

Try / catch

if err := state.Get(key, &v); err != nil {
    if strings.Contains(err.Error(), "failed to acquire lock") {
        // move state to local fs, clear stale lock, retry once
    }
    return err
}

Prevention

When it happens

Trigger: Calling any persistent state method (Data, Get, Delete, DeleteBucket, ForEach, CopyTo) that triggers open while bbolt.Open returns EINVAL, typically from a filesystem that does not support flock.

Common situations: Persistent state (chezmoistate.boltdb) stored on network filesystems (NFS, SMB, CIFS) or filesystems without flock support; containers mounting state dirs from unsupported volumes; two processes contending on unsupported locking.

Related errors


AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01). Data as JSON: /api/errors/9c80827be4a434a2. Report an issue: GitHub.