Ошибки вида ENOSPC: System limit for number of file watchers reached, Too many open files, watch ... failed или жалобы от webpack, vite, VS Code, jest --watch, nodemon, CI-раннеров и даже systemd.path в Debian/Ubuntu встречаются чаще, чем кажется. Обычно проблема не в самом приложении, а в системных лимитах Linux: закончились наблюдатели inotify, инстансы inotify или файловые дескрипторы.
Особенно заметно это на фронтенд-проектах с большим количеством файлов, в монорепозиториях, контейнерных окружениях, self-hosted CI и на серверах, где одновременно работают редакторы, сборщики, синхронизация кода и сервисы, отслеживающие изменения на диске.
Самое неприятное здесь — схожесть симптомов. Один инструмент пишет про watch, второй про ENOSPC, третий про EMFILE, а четвёртый просто перестаёт реагировать на изменения файлов. Поэтому сначала важно не поднимать всё подряд, а понять, какой именно лимит вы упёрли.
Что такое inotify и почему упираются именно в него
inotify — это механизм ядра Linux для отслеживания изменений в файловой системе. Его используют редакторы, IDE, фронтенд-сборщики, file watchers, агенты синхронизации, некоторые демоны и сервисы systemd. Когда приложение хочет следить за каталогом или файлом, оно создаёт watcher через inotify.
В Linux здесь важны три параметра:
fs.inotify.max_user_watches— сколько watcher-ов может создать один пользователь.fs.inotify.max_user_instances— сколько inotify-инстансов может создать один пользователь.fs.inotify.max_queued_events— размер очереди событий для inotify.
Отдельно от этого существует лимит открытых файловых дескрипторов — nofile. Именно он часто даёт ошибку Too many open files, и его очень легко перепутать с ограничениями inotify.
Если вы видите слово
watch, это ещё не значит, что проблема именно вfs.inotify.max_user_watches. Наблюдатели файлов и открытые дескрипторы связаны по смыслу, но это разные лимиты.
Какие симптомы на что похожи
Есть несколько типовых сценариев, по которым можно быстро сузить круг поиска.
Когда не хватает max_user_watches
Обычно это происходит в больших проектах: много директорий, много файлов, много подпапок в node_modules, несколько процессов в режиме watch. Частые сообщения выглядят так:
ENOSPC: System limit for number of file watchers reached
Error: watch ... ENOSPC
Такое часто встречается в сценариях webpack watch linux, vite watch limit, vscode inotify limit.
Когда не хватает max_user_instances
Здесь watcher-ов может быть не так много, но слишком много отдельных процессов создают собственные inotify-инстансы. Например, открыто несколько окон IDE, терминалы с дев-серверами, синхронизация, тесты в watch-режиме, агент CI и фоновые утилиты.
Типичный симптом — приложение не может создать новый экземпляр inotify, хотя часть слежения уже работает.
Когда проблема в nofile
Если сообщение выглядит как Too many open files, EMFILE или сервис не может открыть новый файл, сокет или лог, смотрим в сторону лимита дескрипторов. Это особенно актуально для CI, Node.js, reverse proxy, процессов с большим числом соединений и контейнерных раннеров.
Ключевой момент: увеличение fs.inotify.max_user_watches не лечит Too many open files, если у вас упёрся именно LimitNOFILE или пользовательский ulimit -n. Если тема systemd-лимитов нужна глубже, посмотрите и разберите отдельно настройку лимитов сервисов в systemd.
Для таких задач особенно удобен сервер, где вы полностью контролируете sysctl, systemd и пользовательские лимиты. На практике подобные проблемы проще диагностировать на VDS, чем в жёстко ограниченном окружении.
Быстрая диагностика в Debian/Ubuntu
Начните с просмотра текущих значений sysctl:
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances
sysctl fs.inotify.max_queued_events
Альтернативно можно читать значения напрямую из /proc:
cat /proc/sys/fs/inotify/max_user_watches
cat /proc/sys/fs/inotify/max_user_instances
cat /proc/sys/fs/inotify/max_queued_events
Теперь проверьте лимит открытых файлов в текущей сессии:
ulimit -n
Если проблема у systemd-сервиса, этого недостаточно. У процесса может быть свой лимит, не совпадающий с интерактивной оболочкой:
systemctl show your-service -p LimitNOFILE
Для уже работающего процесса можно посмотреть реальные лимиты так:
cat /proc/$(pgrep -n node)/limits
cat /proc/12345/limits
Как понять, что именно расходует inotify
Универсальной одной команды тут нет, но часто помогает оценка по открытым файловым дескрипторам и поиску inotify в /proc:
find /proc/*/fd -lname anon_inode:inotify 2>/dev/null | wc -l
Эта команда покажет общее количество открытых inotify-дескрипторов в системе. Для поиска процессов-источников:
for pid in /proc/[0-9]*; do n=$(find "$pid/fd" -lname anon_inode:inotify 2>/dev/null | wc -l); if [ "$n" -gt 0 ]; then printf "%s %s
" "$(basename "$pid")" "$n"; fi; done | sort -k2 -n
Если нужен вывод вместе с командной строкой процесса:
for pid in /proc/[0-9]*; do n=$(find "$pid/fd" -lname anon_inode:inotify 2>/dev/null | wc -l); if [ "$n" -gt 0 ]; then printf "%s %s " "$(basename "$pid")" "$n"; tr '\0' ' ' < "$pid/cmdline" 2>/dev/null; printf "
"; fi; done | sort -k2 -n
Это не даст точное число watcher-ов внутри каждого инстанса, но быстро покажет, кто плодит inotify-инстансы.
Как проверить ошибку Too many open files
Сначала посмотрите, сколько дескрипторов уже открыто у процесса:
ls /proc/12345/fd | wc -l
Потом сравните это с лимитом из /proc/12345/limits. Если значения близки, причину вы нашли.

Текущие настройки и порядок применения в Debian/Ubuntu
Когда администратор меняет sysctl и не видит результата после перезапуска сервиса, почти всегда проблема в порядке загрузки конфигурации или в том, что редактировался не тот слой настроек.
В актуальных Debian и Ubuntu параметры sysctl обычно применяются через systemd-sysctl. Это значит, что значения читаются из нескольких каталогов, а приоритет зависит от имени файла и места расположения.
Проверить применённые параметры можно так:
systemctl status systemd-sysctl
systemd-analyze cat-config sysctl.d
Второй вариант особенно полезен, если вы подозреваете, что какой-то пакет или automation уже прописал свои значения, а ваш файл перекрывается позже.
Если вас интересует тема
systemd-sysctl inotify, правильный путь — не править одно и то же в нескольких местах, а держать один понятный override-файл в/etc/sysctl.d/.
Как безопасно увеличить fs.inotify.max_user_watches и max_user_instances
Для большинства рабочих станций разработчика, CI-раннеров и сборочных серверов лучше использовать отдельный файл в /etc/sysctl.d/, а не хаотично редактировать /etc/sysctl.conf.
Создайте файл конфигурации:
sudo sh -c 'cat > /etc/sysctl.d/60-inotify.conf <<"EOF"
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 1024
fs.inotify.max_queued_events = 32768
EOF'
Затем примените настройки:
sudo sysctl --system
И проверьте результат:
sysctl fs.inotify.max_user_watches
sysctl fs.inotify.max_user_instances
sysctl fs.inotify.max_queued_events
Почему именно такие значения? Это не магия и не универсальный стандарт, а практичный стартовый уровень. Значение 524288 для fs.inotify.max_user_watches и 1024 для fs.inotify.max_user_instances обычно покрывает крупные проекты с IDE и несколькими watch-процессами без заметного вреда для сервера.
Если у вас очень плотный CI, несколько runner-ов на одном хосте, большие монорепозитории или много контейнеров, можно поднять лимиты выше, но делать это стоит осознанно и после наблюдения за реальным потреблением.
Когда нужен reboot, а когда нет
Для параметров sysctl перезагрузка обычно не требуется. Достаточно sysctl --system. Но приложения, которые уже получили ошибку и вошли в деградировавшее состояние, иногда нужно перезапустить вручную.
- IDE или remote server VS Code;
- процессы
vite,webpack,nodemon; - агенты CI и раннеры;
- systemd-сервисы, которые работают с file watch.
Как исправить Too many open files отдельно от inotify
Если ваша ошибка — именно Too many open files или EMFILE, проверьте лимиты nofile для пользователя, systemd-юнита и, при необходимости, PAM-сессий.
Для systemd-сервиса
Создайте override:
sudo systemctl edit your-service
И добавьте в открывшийся файл:
[Service]
LimitNOFILE=262144
Затем выполните:
sudo systemctl daemon-reload
sudo systemctl restart your-service
systemctl show your-service -p LimitNOFILE
Для интерактивного пользователя
На системах с PAM можно задать лимиты в /etc/security/limits.d/:
sudo sh -c 'cat > /etc/security/limits.d/60-nofile.conf <<"EOF"
* soft nofile 65535
* hard nofile 262144
EOF'
После этого обычно требуется новая сессия входа. Для SSH — переподключиться, для графической сессии — перелогиниться.
Если сервис запускается через systemd, приоритетнее смотреть именно на LimitNOFILE в unit-файле, а не только на limits.conf.
Когда ошибки упираются не только в inotify, но и в ресурсы юнита в целом, полезно дополнительно проверить лимиты процесса, CPU и память. Для этого пригодится статья про настройку ограничений systemd-сервисов.
Практические сценарии: webpack, Vite, VS Code, CI runner
webpack watch linux
Если webpack --watch внезапно перестал видеть изменения или валится с ENOSPC, почти всегда упёрлись в fs.inotify.max_user_watches. Особенно часто это проявляется в монорепах и проектах с несколькими пакетами.
Поднимите max_user_watches, затем перезапустите процесс сборки. Если ошибка не исчезла и теперь вы видите EMFILE, значит второй потолок — это уже nofile.
vite watch limit
Vite чувствителен к окружению разработки и особенно к bind mount в контейнерах, WSL-подобным сценариям и большим директориям. На нативном Linux проблема обычно решается увеличением inotify-лимитов. Но если проект крутится в контейнере, учитывайте, где именно живёт watcher: внутри контейнера или на хосте.
Если рантайм контейнера наследует ограничения хоста, чинить нужно в первую очередь сам хост Debian/Ubuntu.
vscode inotify limit
VS Code, особенно с расширениями, remote development и несколькими workspace, быстро расходует watcher-ы. Пользователь видит, что поиск работает, но автоперезагрузка, диагностика или отслеживание изменений начинают вести себя нестабильно.
Здесь хорошо помогает увеличение fs.inotify.max_user_watches и fs.inotify.max_user_instances одновременно, потому что IDE нередко создаёт много отдельных наблюдателей и процессов.
ci runner inotify
Self-hosted runner-ы для CI/CD часто запускают параллельные job, сборки фронтенда, тесты в watch-режиме, линтеры и кэширующие процессы. Если несколько pipeline работают одновременно, упереться можно и в inotify, и в nofile.
В таких сценариях рекомендую действовать так:
- Сначала зафиксировать текущие лимиты и реальное потребление.
- Поднять
fs.inotify.max_user_watchesиfs.inotify.max_user_instancesумеренно, а не на максимум. - Для runner-сервиса отдельно проверить
LimitNOFILE. - Ограничить параллелизм, если проблема вызвана не лимитами, а архитектурой job.
Для инфраструктуры, где часто нужны такие ручные настройки, удобнее использовать VDS для CI и сборочных задач с полным доступом к системным параметрам.

Почему не стоит бездумно ставить огромные значения
В интернете часто советуют поставить fs.inotify.max_user_watches = 1048576 или даже больше и забыть. Иногда это нормально, но без контекста такой совет плох.
Каждый watcher потребляет память ядра. На современной машине это редко становится катастрофой само по себе, но на маленьком сервере с несколькими тяжёлыми сервисами бессмысленное завышение лимитов — не лучшая идея. Особенно если первопричина в runaway-процессе, утечке watcher-ов или слишком агрессивном CI.
Хорошая практика — поднять лимит до разумного уровня, проверить, ушла ли проблема, и через несколько дней посмотреть, не растёт ли потребление снова.
Что делать, если после повышения лимитов проблема осталась
Если вы уже изменили fs.inotify.max_user_watches и fs.inotify.max_user_instances, а ошибка не ушла, проверьте следующие моменты:
- Настройки действительно применились через
sysctl --system. - Нужный процесс был перезапущен после изменения.
- Ошибка на самом деле не про
nofile. - Проблема возникает внутри контейнера, а меняете вы хост или наоборот.
- Есть process leak: старые dev-server или IDE-сессии висят в фоне и продолжают держать watcher-ы.
- У вас не inotify-проблема, а особенности сетевой ФС, bind mounts или синхронизации файлов.
Для быстрой санитарной проверки полезно закрыть лишние IDE, остановить старые watch-процессы и повторно проверить число inotify-дескрипторов.
Рекомендуемые значения для типовых сценариев
Абсолютных значений нет, но как практическая отправная точка можно использовать такие ориентиры.
Ноутбук разработчика или dev VM
fs.inotify.max_user_watches = 262144или524288;fs.inotify.max_user_instances = 512или1024;nofileдля пользователя от65535.
Сервер сборки или CI runner
fs.inotify.max_user_watches = 524288или выше по факту нагрузки;fs.inotify.max_user_instances = 1024;LimitNOFILEдля runner-сервиса от131072или262144.
Небольшой production-сервер
Если там нет IDE, фронтенд-сборки и file-watch workload, поднимать inotify про запас обычно не нужно. Но если на сервере крутится deploy-agent, watcher-based синхронизация или systemd.path-юниты, умеренное увеличение тоже бывает полезно.
Если вам нужен сервер под такие кастомные сценарии с полным доступом к системным параметрам, разумно сразу брать VDS для Linux-проектов, а не среду, где системные лимиты менять нельзя.
Минимальный рабочий runbook
Если нужен короткий и безопасный план действий, используйте такой порядок:
- Считать текущие значения
fs.inotify.max_user_watches,fs.inotify.max_user_instancesиulimit -n. - Понять тип ошибки:
ENOSPCилиEMFILE. - Создать override в
/etc/sysctl.d/60-inotify.conf. - Применить
sysctl --system. - При необходимости поднять
LimitNOFILEу нужного systemd-сервиса. - Перезапустить проблемный процесс.
- Проверить, не осталось ли фоновых watcher-процессов.
Вывод
Ошибки fs.inotify.max_user_watches, fs.inotify.max_user_instances, Too many open files и любые сообщения про watch в Debian/Ubuntu — это типичная админская рутина, но решается она не угадыванием, а аккуратной диагностикой. Сначала различаем inotify и nofile, потом проверяем реальные лимиты процесса, затем вносим изменения через /etc/sysctl.d/ и systemd override.
Если делать именно так, а не копировать случайные команды из форумов, проблема обычно уходит быстро и не возвращается при следующем запуске webpack, Vite, VS Code или CI runner.


