This error occurs when your Node.js application exceeds the operating system's limit on the number of file descriptors that can be opened simultaneously. File watchers like fs.watch() are particularly affected, especially in development environments using tools like Webpack, Jest, or file watching services.
The EMFILE error is a system-level error indicating that your application has reached the maximum number of file descriptors the operating system allows a single process to open simultaneously. In Node.js, file descriptors are used not only for files on disk, but also for network sockets, pipes, and other I/O resources. When using fs.watch() or libraries that depend on it (like Webpack dev server, Jest in watch mode, or React Native Metro bundler), each watched file or directory consumes a file descriptor. On Linux systems, this limit is controlled by the inotify subsystem, which has built-in kernel limits on how many watches can be active per user. The default limit on most Linux distributions is 8,192 watches per user, which can be quickly exhausted when watching large folder structures like node_modules or monorepos with thousands of files. macOS uses FSEvents instead of inotify and typically doesn't face this limitation.
First, verify your current system limits to understand what you're working with:
# Check all inotify settings
sysctl fs.inotify
# Check specifically the max user watches
cat /proc/sys/fs/inotify/max_user_watchesThe default is typically 8,192, which may be insufficient for modern JavaScript development.
For a quick fix that lasts until the next reboot:
# Increase to 524,288 watches (common recommendation)
sudo sysctl fs.inotify.max_user_watches=524288
sudo sysctl -pThis will immediately take effect but won't persist after a system restart.
To make the change permanent across reboots:
# Add configuration to sysctl.conf
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
echo fs.inotify.max_user_instances=1024 | sudo tee -a /etc/sysctl.conf
# Reload sysctl configuration
sudo sysctl -pYou may also want to increase max_user_instances if you run multiple watching applications simultaneously.
If you're hitting general file descriptor limits (not inotify-specific):
macOS:
# Check current limit
ulimit -n
# Increase limit for current session
ulimit -n 65536Linux:
# Check current soft and hard limits
ulimit -Sn
ulimit -Hn
# Increase for current session
ulimit -n 65536For permanent changes, edit /etc/security/limits.conf and add:
* soft nofile 65536
* hard nofile 65536Watchman is a file-watching service from Facebook that handles large file trees more efficiently:
# Install Watchman (macOS)
brew install watchman
# Install Watchman (Linux - Ubuntu/Debian)
sudo apt-get install watchman
# Configure Jest to use Watchman
# In your jest.config.js or package.json:
{
"watchman": true
}Watchman is particularly effective with Jest and React Native projects.
Configure your build tools to avoid watching large directories that don't need monitoring:
Webpack:
// webpack.config.js
module.exports = {
watchOptions: {
ignored: /node_modules/,
// Or more specific exclusions:
ignored: ['**/node_modules', '**/dist', '**/.git']
}
};Vite:
// vite.config.js
export default {
server: {
watch: {
ignored: ['**/node_modules/**', '**/dist/**']
}
}
};Jest:
// jest.config.js
{
"watchPathIgnorePatterns": ["node_modules", "dist", "build"]
}After applying changes, verify the issue is resolved:
# Check the new limit
cat /proc/sys/fs/inotify/max_user_watches
# Restart your development server
npm run dev
# or
yarn dev
# Monitor file descriptor usage
lsof -p $(pgrep -f "node") | wc -lIf you still encounter issues, you may need to increase the limits further or investigate if there's a file handle leak in your application.
Platform Differences:
macOS uses FSEvents for file system monitoring, which has no practical upper limit and scales much better than Linux's inotify. This is why EMFILE errors related to file watching are far more common on Linux systems. Windows uses ReadDirectoryChangesW, which has different limitations.
Calculating Required Watches:
If you want to estimate how many watches you need, count the files in your project:
find . -type f | wc -lThen multiply by 1.5-2x to account for directories and buffer. For example, a 50,000 file project should set max_user_watches to at least 100,000.
Docker Considerations:
When running Node.js in Docker containers, the inotify limits are inherited from the host system. You'll need to increase the limits on the Docker host, not inside the container. This is a common source of confusion when developing with Docker.
File Handle Leaks:
If increasing limits doesn't help, you may have a file handle leak. Use lsof to monitor open file descriptors:
# Watch file descriptor count in real-time
watch -n 1 'lsof -p $(pgrep -f "node") | wc -l'If the count continuously increases without bound, you have a leak and should review your code for unclosed streams or file handles.
Monorepo Considerations:
In monorepos with multiple packages, each package's dev server may set up its own watchers. Consider using a tool like Turborepo or Nx which provide smarter file watching strategies and can share file system information across packages.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams