{"record":{"id":"070cf596c00cdc81","repo":"charmbracelet/crush","slug":"lockfileex-w","errorCode":null,"errorMessage":"LockFileEx: %w","messagePattern":"LockFileEx: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/lock/lock_windows.go","lineNumber":33,"sourceCode":"\n// retrySleep is the interval between non-blocking lock retries in the\n// blocking File path.\nconst retrySleep = 100 * time.Millisecond\n\nfunc lockFile(ctx context.Context, f *os.File) (func(), error) {\n\th := windows.Handle(f.Fd())\n\tfor {\n\t\tol := new(windows.Overlapped)\n\t\tflags := uint32(windows.LOCKFILE_EXCLUSIVE_LOCK | windows.LOCKFILE_FAIL_IMMEDIATELY)\n\t\terr := windows.LockFileEx(h, flags, 0, math.MaxUint32, math.MaxUint32, ol)\n\t\tif err == nil {\n\t\t\treturn func() {\n\t\t\t\tol := new(windows.Overlapped)\n\t\t\t\t_ = windows.UnlockFileEx(windows.Handle(f.Fd()), 0, math.MaxUint32, math.MaxUint32, ol)\n\t\t\t}, nil\n\t\t}\n\t\tif !errors.Is(err, windows.ERROR_LOCK_VIOLATION) && !errors.Is(err, windows.ERROR_IO_PENDING) {\n\t\t\treturn nil, fmt.Errorf(\"LockFileEx: %w\", err)\n\t\t}\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, fmt.Errorf(\"acquire lock: %w\", ctx.Err())\n\t\tcase <-time.After(retrySleep):\n\t\t}\n\t}\n}\n\nfunc tryLockFile(f *os.File) (func(), error) {\n\th := windows.Handle(f.Fd())\n\tol := new(windows.Overlapped)\n\tflags := uint32(windows.LOCKFILE_EXCLUSIVE_LOCK | windows.LOCKFILE_FAIL_IMMEDIATELY)\n\tif err := windows.LockFileEx(h, flags, 0, math.MaxUint32, math.MaxUint32, ol); err != nil {\n\t\tif errors.Is(err, windows.ERROR_LOCK_VIOLATION) || errors.Is(err, windows.ERROR_IO_PENDING) {\n\t\t\treturn nil, ErrContended\n\t\t}\n\t\treturn nil, fmt.Errorf(\"LockFileEx: %w\", err)","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/lock/lock_windows.go#L15-L51","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// keep locks off network shares on Windows\nif isUNCPath(filepath.Dir(path)) {\n    return fmt.Errorf(\"lock file must be on a local NTFS path\")\n}","typeGuard":null,"tryCatchPattern":"release, err := lock.File(ctx, path)\nif err != nil && !errors.Is(err, lock.ErrContended) {\n    var errno windows.Errno\n    if errors.As(err, &errno) {\n        return fmt.Errorf(\"LockFileEx error %d: %w\", errno, err)\n    }\n    return err\n}","preventionTips":["Place Windows lock files on local NTFS volumes.","Exclude the data directory from antivirus/backup interference.","Check the wrapped Win32 error code when diagnosing."],"tags":["locking","windows","filesystem"],"backgroundTag":"lockfileex-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}