{"record":{"id":"2bd29060d8445318","repo":"docker/compose","slug":"creating-file-watcher-w","errorCode":null,"errorMessage":"creating file watcher: %w","messagePattern":"creating file watcher: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/watch/watcher_naive.go","lineNumber":308,"sourceCode":"func (d *naiveNotify) add(path string) error {\n\terr := d.watcher.Add(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.numWatches++\n\tnumberOfWatches.Add(1)\n\treturn nil\n}\n\nfunc newWatcher(paths []string) (Notify, error) {\n\tfsw, err := fsnotify.NewWatcher()\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"too many open files\") && runtime.GOOS == \"linux\" {\n\t\t\treturn nil, fmt.Errorf(\"hit OS limits creating a watcher.\\n\" +\n\t\t\t\t\"Run 'sysctl fs.inotify.max_user_instances' to check your inotify limits.\\n\" +\n\t\t\t\t\"To raise them, run 'sudo sysctl fs.inotify.max_user_instances=1024'\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"creating file watcher: %w\", err)\n\t}\n\tMaybeIncreaseBufferSize(fsw)\n\n\terr = fsw.SetRecursive()\n\tisWatcherRecursive := err == nil\n\n\twrappedEvents := make(chan FileEvent)\n\tnotifyList := make(map[string]bool, len(paths))\n\tif isWatcherRecursive {\n\t\tpaths = pathutil.EncompassingPaths(paths)\n\t}\n\tfor _, path := range paths {\n\t\tpath, err := filepath.Abs(path)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"newWatcher: %w\", err)\n\t\t}\n\t\tnotifyList[path] = true\n\t}","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/watch/watcher_naive.go#L290-L326","documentation":"The generic counterpart to the inotify-limit case: fsnotify.NewWatcher() failed for any reason other than the detected 'too many open files' pattern, or the platform is not Linux. The underlying error is wrapped with creating file watcher so the cause survives. Typical causes are fd exhaustion (ulimit -n), EMFILE variants with different wording, or unsupported platforms for the backend.","triggerScenarios":"fsnotify.NewWatcher() returning an error on a non-Linux OS, or a Linux error string not matching 'too many open files' (e.g. localized messages or 'too many open files in system' variants hitting ENFILE — a system-wide fd limit).","commonSituations":"Process fd limit (ulimit -n) exhausted by leaked file descriptors in the app or plugins; ENFILE system-wide fd exhaustion on busy hosts; running on an OS where inotify is unavailable (some minimal containers/seccomp profiles block inotify_init).","solutions":["Check the wrapped cause: EMFILE means raise the process fd limit (`ulimit -n 4096` or LimitNOFILE in systemd); ENFILE means the whole system is out of fds — find the fd hog with `lsof | awk '{print $1}' | sort | uniq -c | sort -rn`.","Verify inotify is permitted: seccomp/cap policies in containers must allow inotify_init1 (try unconfined or adjust the profile).","Reduce concurrent watchers or restart leaking processes to free descriptors."],"exampleFix":"# before: default soft limit causes EMFILE\nulimit -n   # 1024\n# after\nulimit -n 4096\ndocker compose watch","handlingStrategy":"try-catch","validationCode":"// check fd headroom before creating watchers\nvar rlim syscall.Rlimit\nif err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err == nil {\n    if countOpenFds() > int(rlim.Cur)-64 {\n        return fmt.Errorf(\"raise ulimit -n before starting file watchers\")\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    var errno syscall.Errno\n    if errors.As(err, &errno) && (errno == syscall.EMFILE || errno == syscall.ENFILE) {\n        // EMFILE: raise process fd limit (ulimit -n / LimitNOFILE)\n        // ENFILE: system-wide exhaustion — identify fd hogs with lsof, no local retry helps\n    }\n    return err\n}","preventionTips":["Set LimitNOFILE/ulimit -n adequately for long-running dev tooling.","Fix fd leaks in plugins and sidecar processes; monitor /proc/<pid>/fd counts.","In containers, allow inotify syscalls in the seccomp profile."],"tags":["go","docker-compose","watch","fsnotify","file-descriptors","os-limits"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}