Fix: ENOSPC: System Limit for Number of File Watchers Reached

The Error

You’re running a dev server, test watcher, or VS Code, and you get one of these errors:

Node.js / React / Angular / webpack:

Error: ENOSPC: system limit for number of file watchers reached, watch '/home/you/project/src'

Alternate wording:

ENOSPC: no space left on device, watch

VS Code notification:

Visual Studio Code is unable to watch for file changes in this large workspace

macOS (related):

Error: EMFILE, too many open files

These all point to the same root problem: your OS ran out of file watcher slots.

Why This Happens

Development tools watch your files for changes so they can auto-reload, recompile, or update your editor. Each watched file consumes one “watcher” from a limited OS pool.

On Linux, the kernel uses inotify for file watching. The default limit is often 8,192 watchers. That sounds like a lot, but a single node_modules folder can contain tens of thousands of files. Add a framework dev server, a test runner, VS Code, and maybe a bundler — you’ll hit the limit fast.

On macOS, the equivalent limit is the maximum number of open file descriptors (ulimit -n), which defaults to 256 in some configurations. The EMFILE error means you’ve hit that limit.

Common scenarios that trigger this:

  • Large node_modules trees. A mid-sized React or Angular project can easily have 30,000+ files in node_modules. If you’re also hitting npm permission errors or dependency conflicts, fixing those first can reduce bloat.
  • Multiple tools watching simultaneously. VS Code, webpack-dev-server, Jest in watch mode, and nodemon can each create thousands of watchers.
  • Monorepos. Multiple packages, each with their own node_modules, multiply the problem.
  • WSL2. The default inotify limit inside WSL2 is the same low default as a standard Linux install.

Fix 1: Increase the Inotify Watcher Limit (Temporary)

Check your current limit:

cat /proc/sys/fs/inotify/max_user_watches

The default is usually 8192. Increase it immediately:

sudo sysctl fs.inotify.max_user_watches=524288

This takes effect instantly. No restart required. The error should stop.

However, this change is lost on reboot. See Fix 2 to make it permanent.

How to choose a value: 524288 (512K) is the value recommended by the VS Code documentation and used by most Linux distributions that ship a higher default. It uses roughly 256-280 MB of RAM on a 64-bit system (each watch consumes about 540 bytes in kernel memory). For most development machines with 8+ GB of RAM, this is negligible.

Fix 2: Make the Change Permanent

Method A: /etc/sysctl.conf

Add the setting to the system-wide sysctl config:

echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf

Apply it without rebooting:

sudo sysctl -p

Many modern distros prefer drop-in files over editing sysctl.conf directly:

echo "fs.inotify.max_user_watches=524288" | sudo tee /etc/sysctl.d/50-file-watchers.conf

Apply it:

sudo sysctl --system

This is cleaner because it keeps your custom settings separate from the distribution defaults, making upgrades easier.

Verify the change

cat /proc/sys/fs/inotify/max_user_watches

You should see 524288.

Note: You may also want to increase max_user_instances if you run many watcher-heavy processes simultaneously:

echo "fs.inotify.max_user_instances=1024" | sudo tee -a /etc/sysctl.d/50-file-watchers.conf
sudo sysctl --system

The default max_user_instances is 128, which limits how many separate inotify instances a single user can create.

Fix 3: Reduce the Number of Watched Files

Increasing the limit is the quick fix, but the better long-term approach is to stop watching files you don’t need to watch.

Exclude node_modules in your tool config

webpack (webpack.config.js):

module.exports = {
  watchOptions: {
    ignored: /node_modules/,
  },
};

Jest (jest.config.js):

module.exports = {
  watchPathIgnorePatterns: ['<rootDir>/node_modules/'],
};

nodemon (nodemon.json):

{
  "ignore": ["node_modules"]
}

Vite (vite.config.js):

export default defineConfig({
  server: {
    watch: {
      ignored: ['**/node_modules/**'],
    },
  },
});

Use a .watchmanconfig

If you use Watchman (used by Metro bundler in React Native, among others), create a .watchmanconfig in your project root:

{
  "ignore_dirs": ["node_modules", ".git", "build", "dist"]
}

VS Code: exclude folders from watching

Open VS Code settings (Ctrl+, or Cmd+,) and add to settings.json:

{
  "files.watcherExclude": {
    "**/node_modules/**": true,
    "**/.git/objects/**": true,
    "**/.git/subtree-cache/**": true,
    "**/dist/**": true,
    "**/build/**": true,
    "**/coverage/**": true
  }
}

VS Code already excludes node_modules and .git by default in recent versions, but if you have other large generated directories (like dist, build, or coverage), adding them here helps.

Fix 4: macOS — Increase Open File Limits

On macOS, the EMFILE, too many open files error is caused by a low file descriptor limit, not inotify (which is Linux-only).

Check the current limit

ulimit -n

If the output is 256, that’s too low for most Node.js projects.

Increase the limit for the current shell session

ulimit -n 65536

Then restart your dev server in the same terminal.

Make it permanent

Create or edit /Library/LaunchDaemons/limit.maxfiles.plist:

sudo tee /Library/LaunchDaemons/limit.maxfiles.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>limit.maxfiles</string>
    <key>ProgramArguments</key>
    <array>
      <string>launchctl</string>
      <string>limit</string>
      <string>maxfiles</string>
      <string>65536</string>
      <string>200000</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>
EOF

Load it:

sudo launchctl load -w /Library/LaunchDaemons/limit.maxfiles.plist

You can also add ulimit -n 65536 to your ~/.zshrc (or ~/.bashrc) so every new terminal session uses the higher limit.

Fix 5: WSL2-Specific Fix

WSL2 runs a real Linux kernel, so the inotify limit applies. However, WSL2 has a couple of quirks.

Increase the limit inside WSL2

The fix is the same as Linux:

sudo sysctl fs.inotify.max_user_watches=524288

To make it persist across WSL restarts, add it to /etc/sysctl.conf or /etc/sysctl.d/ as described in Fix 2.

However, some older WSL2 kernel versions reset sysctl values when the WSL instance shuts down and restarts. If your setting doesn’t persist, add the sysctl command to your shell profile as a workaround:

# Add to ~/.bashrc or ~/.zshrc
if grep -q microsoft /proc/version 2>/dev/null; then
  sudo sysctl -q fs.inotify.max_user_watches=524288 2>/dev/null
fi

To avoid the sudo password prompt, add a sudoers rule:

echo "$USER ALL=(root) NOPASSWD: $(which sysctl) fs.inotify.max_user_watches=524288" | sudo tee /etc/sudoers.d/inotify

Store your project files inside the WSL filesystem

If your project lives on the Windows filesystem (e.g., /mnt/c/Users/...), file watching is significantly slower and uses more resources due to the 9P filesystem bridge. Move your project into the native WSL2 filesystem (e.g., ~/projects/) for much better performance and fewer watcher issues.

Still Not Working?

Check for an actual disk space problem

ENOSPC can also mean you’ve genuinely run out of disk space — especially when the error message says no space left on device without mentioning “watchers.” Check your disk:

df -h

If a partition is at 100% usage, free up space. Common culprits:

# Clean up old Docker images and containers
docker system prune -a

# Clear npm cache
npm cache clean --force

# Clear systemd journal logs
sudo journalctl --vacuum-size=100M

Docker containers inheriting host limits

Docker containers on Linux share the host kernel, including inotify limits. If you increased the limit on the host but your container still has the error, the container is reading the same /proc/sys/fs/inotify/max_user_watches value as the host. If your container is also running out of memory, see Fix: Docker Exited 137 OOMKilled.

Verify inside the container:

docker exec <container_name> cat /proc/sys/fs/inotify/max_user_watches

If this shows the old value, increase the limit on the host (not inside the container) and restart the container. Containers cannot change sysctl values unless they run with --privileged or the correct --sysctl flag:

docker run --sysctl fs.inotify.max_user_watches=524288 your-image

For Docker Compose:

services:
  app:
    sysctls:
      - fs.inotify.max_user_watches=524288

VS Code still showing the warning

If VS Code still shows “unable to watch for file changes” after increasing the limit:

  1. Reload VS Code (Ctrl+Shift+P > Developer: Reload Window).
  2. Check the limit took effect by running cat /proc/sys/fs/inotify/max_user_watches in the VS Code integrated terminal.
  3. Exclude more directories from watching. Add large generated or vendored directories to files.watcherExclude in your settings (see Fix 3).
  4. Check VS Code’s file watcher by running Ctrl+Shift+P > Developer: Show Logs > select File Watcher from the dropdown. This log shows exactly which paths VS Code is watching.

Systemd service limits

If the error occurs in a Node.js app running as a systemd service (not in your terminal), the service may have its own resource limits. Edit the service file:

sudo systemctl edit your-service

Add:

[Service]
LimitNOFILE=65536

Then reload and restart:

sudo systemctl daemon-reload
sudo systemctl restart your-service

This sets the maximum number of open file descriptors for that specific service, independent of the system-wide inotify limit.


Related: Fix: Port 3000 Is Already in Use

Related Articles