{"record":{"id":"ba6cf1e746e94988","repo":"charmbracelet/crush","slug":"flock-w","errorCode":null,"errorMessage":"flock: %w","messagePattern":"flock: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/lock/lock_unix.go","lineNumber":27,"sourceCode":"\t\"os\"\n\t\"time\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// retrySleep is the interval between non-blocking flock retries in the\n// blocking File path. Small enough that contention resolution feels\n// snappy; large enough that we don't burn a CPU spinning.\nconst retrySleep = 100 * time.Millisecond\n\nfunc lockFile(ctx context.Context, f *os.File) (func(), error) {\n\tfor {\n\t\terr := unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB)\n\t\tif err == nil {\n\t\t\treturn func() { _ = unix.Flock(int(f.Fd()), unix.LOCK_UN) }, nil\n\t\t}\n\t\tif !errors.Is(err, unix.EWOULDBLOCK) {\n\t\t\treturn nil, fmt.Errorf(\"flock: %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\tif err := unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil {\n\t\tif errors.Is(err, unix.EWOULDBLOCK) {\n\t\t\treturn nil, ErrContended\n\t\t}\n\t\treturn nil, fmt.Errorf(\"flock: %w\", err)\n\t}\n\treturn func() { _ = unix.Flock(int(f.Fd()), unix.LOCK_UN) }, nil\n}","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/lock/lock_unix.go#L9-L45","documentation":"lockFile retries unix.Flock with LOCK_EX|LOCK_NB in a loop. If Flock fails with an error other than EWOULDBLOCK (i.e., not simple contention), the retry loop aborts and this error wraps the raw errno. Typical errnos: EBADF (bad fd), EINTR handling, EOL3/NOLCK (system lock table full), or EDEADLK.","triggerScenarios":"Calling lock.File on a platform where unix.Flock fails with a non-contention error, e.g. the file descriptor became invalid, the filesystem does not support flock (some network mounts like certain NFS configs), or the kernel lock table is exhausted.","commonSituations":"Lock file on an NFS/network mount that doesn't support flock; running in a container/sandbox that blocks flock; heavy lock usage exhausting the system-wide lock table.","solutions":["Move the lock file (and data dir) onto a local filesystem that supports flock instead of a network mount.","Inspect the wrapped errno to identify the cause (EBADF, ENOLCK, etc.) and address it specifically.","If running in a restricted sandbox/container, ensure the filesystem allows flock or run outside the sandbox.","Reduce the number of simultaneous file locks if the system lock table is exhausted."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// avoid unsupported filesystems for lock files\nif isNetworkMount(filepath.Dir(path)) {\n    return fmt.Errorf(\"lock file must be on a local filesystem supporting flock\")\n}","typeGuard":null,"tryCatchPattern":"release, err := lock.File(ctx, path)\nif err != nil && !errors.Is(err, lock.ErrContended) {\n    return fmt.Errorf(\"flock unavailable on this filesystem: %w\", err)\n}","preventionTips":["Keep lock files on local disks, not NFS/SMB mounts.","Check the wrapped errno to diagnose EBADF vs ENOLCK quickly.","Verify sandbox/container policies permit flock before deployment."],"tags":["locking","flock","unix","filesystem"],"backgroundTag":"flock-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}