Skip to content
This repository was archived by the owner on Aug 18, 2025. It is now read-only.

Commit 0bf9001

Browse files
author
Jonathan Yu
committed
chore: document inotify watch limit
Add a guide explaining the inotify watch limit problem, including instructions to diagnose and resolve it.
1 parent eb31789 commit 0bf9001

File tree

2 files changed

+274
-1
lines changed

2 files changed

+274
-1
lines changed
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
---
2+
title: Troubleshooting inotify Watcher Limit Problems
3+
description: Learn how to resolve problems related to the inotify Watcher Limit.
4+
---
5+
6+
The [`inotify` facility] allows programs to monitor files and directories for
7+
changes, so that they will receive an event immediately whenever a user or
8+
program modifies the file or directory. Many such programs can fall back to
9+
periodically checking files and directories for changes, also known as polling.
10+
Using polling avoids the watch limit, but may result in higher system loading
11+
and a longer interval for the program to detect changes.
12+
13+
`inotify` requires kernel resources (memory and processor) for each file it
14+
tracks. As a result, the Linux kernel limits the number of file watchers that
15+
each user can register. The default settings vary according to the host system
16+
distribution; on Ubuntu 20.04 LTS, the default limit is 8,192 watches per instance
17+
18+
[`inotify` facility]: https://en.wikipedia.org/wiki/Inotify
19+
20+
With some applications and tools, including Webpack or [code-server], you may
21+
encounter an error similar to the following:
22+
23+
> Watchpack Error (watcher): Error: ENOSPC: System limit for number of file
24+
> watchers reached, watch '/some/path'
25+
26+
[code-server]: https://github.com/cdr/code-server
27+
28+
On a 64-bit system, each `inotify` watch that programs register will consume
29+
approximately 1 kB of kernel memory, which cannot be swapped to disk and is not
30+
counted against the environment memory limit setting.
31+
32+
## Diagnosis
33+
34+
If the total number of watchers is close to the `max_user_watches` setting, then
35+
it is likely that you are encountering this limit.
36+
37+
### Check tunable settings
38+
39+
There are three kernel tuning options related to the `inotify` system:
40+
41+
- `fs.inotify.max_queued_events`, which defines an upper bound on the number of
42+
file notification events pending delivery to programs.
43+
- `fs.inotify.max_user_instances`, which determines the maximum number of
44+
`inotify` instances per user. Programs using `inotify` will typically create
45+
a single _instance_, so this limit is unlikely to cause issues.
46+
- `fs.inotify.max_user_watches`, which defines the maximum number of files and
47+
folders that programs can monitor for changes.
48+
49+
For additional detail regarding the `inotify` system, please see
50+
[inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html).
51+
52+
To see the values for these settings applicable to your environment, run the
53+
following commands:
54+
55+
```shell-session
56+
$ sysctl fs.inotify.{max_queued_events,max_user_instances,max_user_watches}
57+
fs.inotify.max_queued_events = 16384
58+
fs.inotify.max_user_instances = 128
59+
fs.inotify.max_user_watches = 8192
60+
```
61+
62+
Because these settings are not namespace-aware, the values will be the same
63+
regardless of whether you run the commands on the host system or inside a
64+
container running on that host.
65+
66+
### Identify inotify consumers
67+
68+
To identify the programs consuming `inotify` watches, you can use a script that
69+
summarizes the information available in the `/proc` filesystem, such as
70+
[`inotify-consumers`]. This script will show the names of programs along with
71+
the number of `inotify` watches registered with the kernel:
72+
73+
```shell-session
74+
$ ./inotify-consumers
75+
INOTIFY
76+
WATCHER
77+
COUNT PID USER COMMAND
78+
--------------------------------------
79+
269 254560 coder /opt/coder/code-server/lib/node
80+
/opt/coder/code-server/lib/vscode/out/bootstrap-fork --type=watcherService
81+
5 1722 coder /opt/coder/code-server/lib/node
82+
/opt/coder/code-server/lib/vscode/out/vs/server/fork
83+
2 254538 coder /opt/coder/code-server/lib/node
84+
/opt/coder/code-server/lib/vscode/out/bootstrap-fork --type=extensionHost
85+
2 1507 coder gpg-agent --homedir /home/coder/.gnupg
86+
--use-standard-socket --daemon
87+
88+
278 WATCHERS TOTAL COUNT
89+
```
90+
91+
Please note that this is a third-party script published by an individual who is
92+
not affiliated with Coder, and as such, we cannot provide a warranty or support
93+
for its usage.
94+
95+
[`inotify-consumers`]: https://github.com/fatso83/dotfiles/blob/master/utils/scripts/inotify-consumers
96+
97+
To see the specific files and directories that the tools track for changes, you
98+
can use `strace` to monitor invocations of the `inotify_add_watch` system call:
99+
100+
```shell-session
101+
$ strace --follow-forks --trace='inotify_add_watch' inotifywait --quiet test
102+
inotify_add_watch(3, "test", IN_ACCESS|IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE|
103+
IN_CLOSE_NOWRITE|IN_OPEN|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE|
104+
IN_DELETE_SELF|IN_MOVE_SELF) = 1
105+
```
106+
107+
This shows that the `inotifywait` command is listening for notifications related
108+
to the `test` file.
109+
110+
## Resolution
111+
112+
If you encounter the file watcher limit, there are two potential resolutions:
113+
either reduce the number of file watcher registrations, or increase the maximum
114+
file watcher limit. We recommend attempting to reduce the file watcher
115+
registrations first, because increasing the number of file watches may result
116+
in high processor utilization.
117+
118+
### Reduce watchers
119+
120+
Many applications include files that change very rarely, and developers often
121+
do not consider these to be part of _their_ application. For example, this may
122+
include third-party dependencies stored in `node_modules`. Tools may watch for
123+
changes to these files and folders, consuming `inotify` watchers.
124+
125+
These tools typically provide configuration settings to exclude certain files,
126+
paths, and patterns from file watching. For example, Visual Studio Code and
127+
`code-server` apply the following [user workspace setting] by default:
128+
129+
```json
130+
"files.watcherExclude": {
131+
"**/.git/objects/**": true,
132+
"**/.git/subtree-cache/**": true,
133+
"**/node_modules/**": true,
134+
"**/.hg/store/**": true
135+
},
136+
```
137+
138+
Consider adding other infrequently-changed files to this list, which will cause
139+
Visual Studio Code to poll for changes to those files periodically. For other
140+
software tools, please see the respective user manual.
141+
142+
[user workspace setting]: https://code.visualstudio.com/docs/getstarted/settings
143+
144+
### Increase the watch limit
145+
146+
You can increase the kernel tunable option to increase the maximum number of
147+
`inotify` watches for each user. This is a global setting that applies to all
148+
users sharing the same system, or _Node_ in Kubernetes parlance. To do this,
149+
modify the `sysctl` configuration file, or apply a DaemonSet to the Kubernetes
150+
cluster to apply that change to all nodes automatically.
151+
152+
For example, create a file called `/etc/sysctl.d/watches.conf` and include the
153+
following contents:
154+
155+
```text
156+
fs.inotify.max_user_watches = 65536
157+
```
158+
159+
Alternatively, you can use the following DaemonSet with `kubectl apply`:
160+
161+
```yaml
162+
apiVersion: apps/v1
163+
kind: DaemonSet
164+
metadata:
165+
name: more-fs-watchers
166+
namespace: kube-system
167+
labels:
168+
app: more-fs-watchers
169+
k8s-app: more-fs-watchers
170+
spec:
171+
selector:
172+
matchLabels:
173+
k8s-app: more-fs-watchers
174+
template:
175+
metadata:
176+
labels:
177+
name: more-fs-watchers
178+
k8s-app: more-fs-watchers
179+
annotations:
180+
seccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default
181+
apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
182+
spec:
183+
nodeSelector:
184+
kubernetes.io/os: linux
185+
initContainers:
186+
- name: sysctl
187+
image: alpine:3
188+
command:
189+
- sysctl
190+
- -w
191+
- fs.inotify.max_user_watches=16384
192+
resources:
193+
requests:
194+
cpu: 10m
195+
memory: 1Mi
196+
limits:
197+
cpu: 100m
198+
memory: 5Mi
199+
securityContext:
200+
# We need to run as root in a privileged container to modify
201+
# /proc/sys on the host (for sysctl)
202+
runAsUser: 0
203+
privileged: true
204+
readOnlyRootFilesystem: true
205+
capabilities:
206+
drop:
207+
- ALL
208+
containers:
209+
- name: pause
210+
image: k8s.gcr.io/pause:3.5
211+
command:
212+
- /pause
213+
resources:
214+
requests:
215+
cpu: 10m
216+
memory: 1Mi
217+
limits:
218+
cpu: 100m
219+
memory: 5Mi
220+
securityContext:
221+
runAsNonRoot: true
222+
runAsUser: 65535
223+
allowPrivilegeEscalation: false
224+
privileged: false
225+
readOnlyRootFilesystem: true
226+
capabilities:
227+
drop:
228+
- ALL
229+
terminationGracePeriodSeconds: 5
230+
```
231+
232+
This DaemonSet will ensure that the corresponding Pod runs on _every_ Linux node
233+
in the cluster. When new nodes join the cluster, such as when an autoscaling
234+
event occurs, the DaemonsSet will ensure that the pod runs on that node as well.
235+
You may delete the DaemonSet by running the following command:
236+
237+
```shell-session
238+
$ kubectl delete --namespace=kube-system daemonset more-fs-watchers
239+
daemonset.apps "more-fs-watchers" deleted
240+
```
241+
242+
However, note that the setting will persist until the node restarts or until
243+
another program sets the `fs.inotify.max_user_watches` setting.
244+
245+
## See Also
246+
247+
- Resources for Visual Studio Code and code-server:
248+
- [User and Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings),
249+
in particular, the setting called `files.watcherExclude`.
250+
- [VS Code Setting: files.watcherExclude](https://youtu.be/WMNua0ob6Aw)
251+
(YouTube).
252+
- [My ultimate VSCode
253+
configuration](https://dev.to/vaidhyanathan93/ulitmate-vscode-configuration-4i2o),
254+
a blog post describing a user's preferred settings, including file exclusions.
255+
- [Filesystem notification, part 1: An overview of dnotify and inotify](https://lwn.net/Articles/604686/)
256+
and [Filesystem notification, part 2: A deeper investigation of inotify](https://lwn.net/Articles/605128/)
257+
examine the `inotify` mechanism in detail, along with its predecessor,
258+
`dnotify`.
259+
- Microsoft's Language Server Protocol (LSP) specification describes an approach
260+
for using file watch notifications:
261+
[DidChangeWatchedFiles Notification](https://microsoft.github.io/language-server-protocol/specification#workspace_didChangeWatchedFiles).
262+
Visual Studio Code and code-server, along with many other editors, uses this
263+
protocol for programming language support, and the same constraints and
264+
limitations apply to those tools.
265+
- Kubernetes provides a mechanism for [Setting Sysctls for a Pod](https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/#setting-sysctls-for-a-pod).
266+
However, the `inotify` tunable options cannot be set this way, so this is not
267+
applicable to resolving this issue.
268+
- [INotify watch limit](https://blog.passcod.name/2017/jun/25/inotify-watch-limit.html)
269+
provides additional context on the problem and its resolution.
270+
- [inotify(7)](https://man7.org/linux/man-pages/man7/inotify.7.html), the Linux
271+
manual page related to the `inotify` system call.
272+
- [Kernel Korner - Intro to inotify](https://www.linuxjournal.com/article/8478)

manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@
117117
"children": [
118118
{ "path": "./guides/admin/resources.md" },
119119
{ "path": "./guides/admin/usage-monitoring.md" },
120-
{ "path": "./guides/admin/helm-charts.md" }
120+
{ "path": "./guides/admin/helm-charts.md" },
121+
{ "path": "./guides/admin/inotify-watch-limits.md" }
121122
]
122123
},
123124
{

0 commit comments

Comments
 (0)