Что значит inotify ENOSPC и почему это не про место на диске
Когда IDE или сборщик пишет ENOSPC: System limit for number of file watchers reached, первая мысль — проверить свободное место. Но в контексте inotify код ENOSPC почти всегда означает «закончился системный ресурс» (лимит), а не «диск заполнен».
inotify — подсистема ядра Linux для уведомлений о событиях в файловой системе: изменение файла, создание, удаление и т.д. На неё опираются dev-серверы, IDE, сборщики и CI-агенты.
Проблема возникает, когда суммарное число наблюдений (watches) или экземпляров inotify (instances) превышает лимит, либо когда очередь событий переполняется (обработчик не успевает).
Три главных лимита: watches, instances и queued events
Практически все случаи ENOSPC упираются в один из трёх параметров sysctl:
fs.inotify.max_user_watches— сколько «точек наблюдения» (watch) может создать один пользователь (UID). Обычно watch ставится на директории (реже на отдельные файлы — зависит от инструмента).fs.inotify.max_user_instances— сколько экземпляров inotify может создать один пользователь. Условно: сколько независимых «клиентов» inotify может жить параллельно.fs.inotify.max_queued_events— максимальный размер очереди событий. При шторме событий и медленном обработчике возможны переполнения и пропуски.
Увеличение лимитов лечит симптом. Если инструмент наблюдает каталог, куда сам же пишет артефакты, вы получите шторм событий и нагрузку даже при больших значениях.
В продакшене и на сборочных агентам это особенно заметно: много проектов, много параллели, большие рабочие каталоги. Если вам нужна отдельная машина под CI/сборки, удобнее держать преднастроенный профиль sysctl на VDS, чтобы ловить меньше «внезапных» падений вотчеров.

Как выглядит ошибка на практике (VS Code, webpack, PhpStorm, CI)
Типичные сообщения, которые вы увидите в логах или UI:
- Node.js/webpack/vite/nodemon:
ENOSPC: System limit for number of file watchers reached. - VS Code: перестаёт обновляться дерево файлов, ломается auto-reload, появляются уведомления о проблемах с file watcher.
- PhpStorm/WebStorm: File Watchers отваливаются, индексация работает нестабильно, появляются предупреждения о нехватке watchers.
- CI runners: сборка падает только на конкретном агенте, где одновременно крутится много джобов и workspace большой.
Иногда рядом всплывает «too many open files». Это уже лимиты файловых дескрипторов (FD) и ulimit — отдельная, но часто сопутствующая история. Если нужно быстро закрыть оба класса проблем, посмотрите мой разбор про лимиты FD и inotify: как связаны nofile и inotify и где их настраивать.
Быстрая диагностика: текущие значения 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
Как понять, во что именно вы упираетесь
Если сообщение явно говорит про watchers — почти всегда достаточно поднять fs.inotify.max_user_watches. Если на машине много сервисов от одного пользователя (например, runner запускает всё под gitlab-runner) — можно упереться в fs.inotify.max_user_instances.
Если же у вас интенсивная генерация файлов (компиляция, синхронизация артефактов, автоформатирование), и при этом наблюдается «буря» событий, узким местом иногда становится fs.inotify.max_queued_events.
Временное решение до перезагрузки (проверить гипотезу)
Чтобы быстро подтвердить, что проблема именно в лимитах inotify, поднимите значения на лету. Это не переживёт перезагрузку:
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024
sudo sysctl -w fs.inotify.max_queued_events=32768
Если после этого IDE/сборка/пайплайн ожили — фиксируем настройку правильно через sysctl.d.
Постоянная настройка через sysctl.d (правильный способ)
На современных дистрибутивах удобнее завести отдельный файл в /etc/sysctl.d/, чтобы не смешивать параметры и проще откатывать.
Создайте, например, /etc/sysctl.d/99-inotify.conf:
sudo sh -c 'cat > /etc/sysctl.d/99-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
Или примените только один файл:
sudo sysctl -p /etc/sysctl.d/99-inotify.conf
systemd-sysctl: порядок применения и «почему не применилось»
Если после перезагрузки значения снова «не те», скорее всего, есть переопределение из другого файла sysctl.d, либо настройки применяются в неожиданном порядке.
Проверьте состояние сервиса и итоговую «склейку» конфигов:
systemctl status systemd-sysctl
systemd-analyze cat-config sysctl.d
В выводе systemd-analyze cat-config sysctl.d видно, какие файлы влияют на итог и кто переопределил ваши значения.
Какие значения ставить: практические ориентиры
Универсального числа нет: влияет размер репозитория, количество параллельных процессов и то, наблюдаете ли вы тяжёлые каталоги (вроде node_modules), vendor-директории, артефакты сборки и кеши.
Ориентиры, которые чаще всего решают проблему на dev/CI без фанатизма:
fs.inotify.max_user_watches: 262144 или 524288 для больших проектов и монореп.fs.inotify.max_user_instances: 512 или 1024, если много параллельных процессов (IDE + несколько watch + тесты).fs.inotify.max_queued_events: 16384–32768, если есть признаки шторма событий.
На CI runners помните: один пользователь может обслуживать много джобов. Иногда эффективнее не только поднять лимиты, но и ограничить параллелизм исполнителей на одном агенте, чтобы не умножать watchers на N.

Как найти «пожирателя» watchers
Частая ситуация: лимит «съедает» не тот процесс, на который вы думаете (например, не сборщик, а IDE или несколько забытых dev-серверов в фоне).
Приблизительно потребление inotify можно оценить по дескрипторам anon_inode:inotify. Пример для текущего процесса:
ls -l /proc/self/fd | grep -c inotify
Чтобы получить топ процессов по inotify (нужны права root):
sudo lsof -n | grep -F anon_inode:inotify | awk '{print $1, $2}' | sort | uniq -c | sort -nr | head
Дальше действуйте точечно: закрывайте лишние проекты/IDE, убирайте лишние watch-процессы, добавляйте исключения каталогов в конфиги сборки/инструментов.
Частые причины, почему лимитов не хватает
Большие деревья: node_modules, vendor, .git, build
Современные проекты легко создают десятки и сотни тысяч файлов. Если watcher рекурсивно подписывается на всё подряд, fs.inotify.max_user_watches заканчивается мгновенно.
Практика: исключайте тяжёлые каталоги из наблюдения и индексации. В сборщиках это обычно ignore/exclude, в IDE — «Excluded» для build output, кешей, зависимостей.
Watcher смотрит на директорию, куда сам же пишет
Классика: сборка пишет артефакты в папку внутри проекта, а watcher наблюдает весь проект целиком. Получается петля событий «изменение → сборка → артефакты → события», и тогда может упереться даже fs.inotify.max_queued_events.
CI runners: много параллели и «хвосты» процессов
На CI проблема часто проявляется «внезапно», потому что runners крутят несколько задач одновременно. Каждая задача поднимает собственные watchers, а иногда ещё и сервисы (dev server, тестовый раннер).
Если агенты живут долго, следите за «хвостами»: зависшие процессы продолжают держать watchers. Если вы строите пайплайны на inotify-триггерах, может быть полезен подход с systemd path units; см. также: systemd Path + inotify для CI и фоновых задач.
Связанный класс проблем: «too many open files» и лимиты nofile
ENOSPC в inotify и «too many open files» часто приходят парой: инструмент одновременно открывает много файлов и ставит много наблюдений. Поэтому повышение только fs.inotify.* может дать частичный эффект.
Быстрая проверка FD лимитов:
ulimit -n
cat /proc/$(pidof -s code)/limits | grep -i open
Если лимит мал, лечите оба слоя: sysctl для inotify и лимиты FD (ulimit/systemd LimitNOFILE).
Мини-рукбук для админа: что делать, если упало на CI/сборочном агенте
- Зафиксировать симптом: текст ошибки (watches/instances/queue), какой процесс и под каким пользователем.
- Проверить текущие значения:
sysctl fs.inotify.max_user_watches fs.inotify.max_user_instances fs.inotify.max_queued_events. - Временно поднять лимиты через
sysctl -wи подтвердить, что пайплайн/вотчер ожили. - Внести постоянную настройку в
/etc/sysctl.d/99-inotify.conf, применитьsudo sysctl --system. - Если повторяется: найти топ процессов по
anon_inode:inotifyи привести в порядок ignore/exclude. - Проверить лимиты FD (
ulimit -n, systemd unit overrides), если рядом есть «too many open files».
Проверка результата и контроль изменений
После применения убедитесь, что значения реально изменились:
sysctl fs.inotify.max_user_watches fs.inotify.max_user_instances fs.inotify.max_queued_events
Если после перезагрузки снова старые значения — ищите переопределение:
systemd-analyze cat-config sysctl.d
И не забывайте про гигиену watch-настроек: исключения для зависимостей и артефактов часто дают больший эффект, чем бесконечное повышение лимитов.


