charmbracelet/crush · error
LockFileEx: %w
Error message
LockFileEx: %w
What it means
On Windows, lockFile calls windows.LockFileEx with LOCKFILE_EXCLUSIVE_LOCK, retrying on ERROR_LOCK_VIOLATION/ERROR_IO_PENDING (contention). If LockFileEx returns any other error, the loop aborts and this error wraps the Win32 error. It indicates a real locking failure, not another holder of the lock.
Source
Thrown at internal/lock/lock_windows.go:33
// retrySleep is the interval between non-blocking lock retries in the
// blocking File path.
const retrySleep = 100 * time.Millisecond
func lockFile(ctx context.Context, f *os.File) (func(), error) {
h := windows.Handle(f.Fd())
for {
ol := new(windows.Overlapped)
flags := uint32(windows.LOCKFILE_EXCLUSIVE_LOCK | windows.LOCKFILE_FAIL_IMMEDIATELY)
err := windows.LockFileEx(h, flags, 0, math.MaxUint32, math.MaxUint32, ol)
if err == nil {
return func() {
ol := new(windows.Overlapped)
_ = windows.UnlockFileEx(windows.Handle(f.Fd()), 0, math.MaxUint32, math.MaxUint32, ol)
}, nil
}
if !errors.Is(err, windows.ERROR_LOCK_VIOLATION) && !errors.Is(err, windows.ERROR_IO_PENDING) {
return nil, fmt.Errorf("LockFileEx: %w", err)
}
select {
case <-ctx.Done():
return nil, fmt.Errorf("acquire lock: %w", ctx.Err())
case <-time.After(retrySleep):
}
}
}
func tryLockFile(f *os.File) (func(), error) {
h := windows.Handle(f.Fd())
ol := new(windows.Overlapped)
flags := uint32(windows.LOCKFILE_EXCLUSIVE_LOCK | windows.LOCKFILE_FAIL_IMMEDIATELY)
if err := windows.LockFileEx(h, flags, 0, math.MaxUint32, math.MaxUint32, ol); err != nil {
if errors.Is(err, windows.ERROR_LOCK_VIOLATION) || errors.Is(err, windows.ERROR_IO_PENDING) {
return nil, ErrContended
}
return nil, fmt.Errorf("LockFileEx: %w", err)View on GitHub (pinned to 7944b8e522)
Solutions
- Move the lock file to a local NTFS path instead of a network share.
- Check the wrapped Win32 error code for the exact cause (handle invalid, access denied, etc.).
- Exclude the data directory from antivirus/backup tools that may disrupt lock operations.
- Recreate the lock file if it was deleted or replaced while the process held a handle.
Defensive patterns
Strategy: fallback
Validate before calling
// keep locks off network shares on Windows
if isUNCPath(filepath.Dir(path)) {
return fmt.Errorf("lock file must be on a local NTFS path")
} Try / catch
release, err := lock.File(ctx, path)
if err != nil && !errors.Is(err, lock.ErrContended) {
var errno windows.Errno
if errors.As(err, &errno) {
return fmt.Errorf("LockFileEx error %d: %w", errno, err)
}
return err
} Prevention
- Place Windows lock files on local NTFS volumes.
- Exclude the data directory from antivirus/backup interference.
- Check the wrapped Win32 error code when diagnosing.
When it happens
Trigger: Calling lock.File on Windows where LockFileEx fails with an unexpected Win32 error: invalid handle, unsupported filesystem (some network shares), or an access-rights problem on the handle opened by os.OpenFile.
Common situations: Lock file located on a network share (SMB) that doesn't support byte-range locks; antivirus or backup software interfering with file locks; handle corruption after the file was deleted underneath the process.
Related errors
- acquire config lock: %w
- open lock file %q: %w
- flock: %w
- acquire lock: %w
- failed to create parent directories: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/070cf596c00cdc81.
Report an issue: GitHub.