{"record":{"id":"fa93c2332705baec","repo":"charmbracelet/crush","slug":"acquire-lock-w-fa93c2","errorCode":null,"errorMessage":"acquire lock: %w","messagePattern":"acquire lock: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/lock/lock_windows.go","lineNumber":37,"sourceCode":"\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)\n\t}\n\treturn func() {\n\t\tol := new(windows.Overlapped)\n\t\t_ = windows.UnlockFileEx(windows.Handle(f.Fd()), 0, math.MaxUint32, math.MaxUint32, ol)","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/lock/lock_windows.go#L19-L55","documentation":"In the Windows lockFile retry loop, when LockFileEx reports contention (ERROR_LOCK_VIOLATION/ERROR_IO_PENDING) the function retries until the context is done. If the context is cancelled or its deadline lapses while the lock is still held by another process, this error wrapping ctx.Err() is returned.","triggerScenarios":"Calling lock.File on Windows with a bounded context while another process holds the exclusive LockFileEx lock for longer than the deadline.","commonSituations":"Second instance of the app started against the same data directory on Windows; the first instance crashed without releasing an OS lock is rare (Windows releases on handle close), so this usually means a genuinely running contender; too-short timeout.","solutions":["Identify and close the other process holding the lock (Task Manager / handle inspection).","Extend or drop the context deadline (context.Background() waits indefinitely).","Use lock.TryFile when you want immediate ErrContended feedback instead of waiting.","Reboot if a zombie process holds the handle and cannot be identified."],"exampleFix":"// before\nrelease, err := lock.File(ctx, lockPath) // ctx has 1s timeout\n// after\nwaitCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nrelease, err := lock.File(waitCtx, lockPath)\nif errors.Is(err, context.DeadlineExceeded) {\n    return fmt.Errorf(\"lock %s held by another process\", lockPath)\n}","handlingStrategy":"retry","validationCode":"tr, err := lock.TryFile(path)\nif errors.Is(err, lock.ErrContended) {\n    return fmt.Errorf(\"another instance on this machine holds the lock\")\n}","typeGuard":null,"tryCatchPattern":"ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nrelease, err := lock.File(ctx, path)\nif errors.Is(err, context.DeadlineExceeded) {\n    return fmt.Errorf(\"lock %s still held after timeout\", path)\n}","preventionTips":["Use generous timeouts on Windows where server startup may be slow.","Check for other running instances before long waits.","Use TryFile for fail-fast user-facing checks and File for background waits."],"tags":["locking","windows","context","timeout"],"backgroundTag":"lock-acquisition-timeout","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}