Node.js Error

Error: ENOSPC: no space left on device

error code: ENOSPC  ·  also: System limit for number of file watchers reached

Complete reference — two distinct root causes, every fix, platform-specific guidance for Linux, macOS, Docker, and CI/CD.

Quick Answer: Error: ENOSPC in Node.js has two completely different root causes. (1) Inotify watcher limit (Linux only, most common in dev) — the kernel's file-watching slots are exhausted by webpack/Vite/Jest/nodemon watching node_modules. Fix: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p, then exclude node_modules from your watcher config. (2) Disk space full — the filesystem is genuinely out of space during npm install, a build write, or a Docker layer push. Fix: df -h to confirm, then npm cache clean --force, docker system prune -a, or expand the volume.

What is ENOSPC?

ENOSPC stands for Error NO SPaCe — a POSIX system error code that the Linux/macOS kernel emits when a resource quota is exhausted. In Node.js it surfaces as two distinct error messages that share the same code: 'ENOSPC':

The naming is misleading: the inotify variant appears to be about disk space but is actually about an in-kernel watch-slot quota. Both variants return errno: -28 on Linux because the kernel uses ENOSPC for any exhausted resource, including the inotify table.

Exact error strings you will see in Node.js:
Error: ENOSPC: System limit for number of file watchers reached, watch '/project/src'
Watchpack Error (watcher): Error: ENOSPC: System limit for number of file watchers reached, watch '/project'
Error: ENOSPC: no space left on device, write '/project/dist/bundle.js'
npm ERR! code ENOSPC
npm ERR! errno -28
npm ERR! syscall write
Error: ENOSPC: no space left on device, mkdir '/tmp/npm-...'

Full Error Examples

Inotify watcher limit variant (most common in development)

Error: ENOSPC: System limit for number of file watchers reached, watch '/home/user/project/node_modules'
    at FSWatcher.<anonymous> (node:fs:2341:19)
    at FSWatcher.emit (node:events:513:28)
    at FSWatcher.start (node:internal/fs/watchers:248:10) {
  errno: -28,
  code: 'ENOSPC',
  syscall: 'watch',
  filename: '/home/user/project/node_modules'
}

Disk-full variant (common in CI/CD and containers)

npm ERR! code ENOSPC
npm ERR! syscall write
npm ERR! errno -28
npm ERR! Error: ENOSPC: no space left on device, write '/home/runner/.npm/_cacache/tmp/...'

Error: ENOSPC: no space left on device, write '/project/dist/main.js'
    at Object.writeSync (node:fs:714:3)
    at writeAllSync (node:fs:413:12) {
  errno: -28,
  code: 'ENOSPC',
  syscall: 'write'
}

Key diagnostic fields on the error object:

FieldWatcher variant valueDisk variant valueMeaning
code'ENOSPC''ENOSPC'Always ENOSPC for both variants
syscall'watch''write', 'mkdir', 'open'Key differentiatorwatch = inotify; write/mkdir = disk full
errno-28-28Linux ENOSPC constant; both variants use -28
filenameThe watched pathThe file being writtenExact path that triggered the error
How to instantly tell which variant you have: Check err.syscall. If it is 'watch', you have the inotify limit problem — disk space is irrelevant. If it is 'write', 'mkdir', or 'open', run df -h to confirm disk is full.

All Causes at a Glance

CausePlatformTypical triggerFix
Linux inotify watch limit exhaustedLinux onlywebpack/Vite/Jest/nodemon dev server startup watching node_modulesRaise fs.inotify.max_user_watches via sysctl
node_modules included in file watchingLinuxDefault chokidar/watchpack config watches entire project treeAdd ignored: /node_modules/ to watcher config
Multiple dev servers open simultaneouslyLinuxSeveral terminal tabs each running a dev serverClose other projects; raise inotify limit
Docker container inherits low host inotify limitLinux (Docker)Dev server inside container fails to watch filesRaise limit on Docker host; use CHOKIDAR_USEPOLLING=true
Disk space genuinely fullAll platformsnpm install or build write fails with syscall: 'write'df -h to confirm, then free space
npm cache consuming diskAll platformsCI runner disk fills after many installsnpm cache clean --force
Docker overlay2 / image cache fullLinux (Docker host)Build produces image layers that fill the diskdocker system prune -a
Inode exhaustion (disk blocks free but inodes full)LinuxHuge number of tiny files (e.g. nested node_modules)df -i to check; remove unnecessary small files
tmpfs /tmp too smallLinuxnpm writes temp files to an in-memory /tmp filesystem with a small quotaExpand /tmp mount or set npm config set tmp /some/other/path
GitHub Actions / GitLab CI disk quotaCI/CD14 GB runner disk consumed by pre-installed tools + large node_modules + build artifactsRemove pre-installed tools before build; use caching
---

Root Cause A – Inotify File Watcher Limit (Linux)

This is the most common ENOSPC in Node.js development. On Linux, the kernel's inotify subsystem allows user-space processes to watch files and directories for changes. Each watched path consumes one inotify watch slot. The kernel limits the total number of watch slots per user via the sysctl parameter fs.inotify.max_user_watches, which defaults to 8192 on most Linux distributions (Ubuntu 20.04 raised this to 65535, but it is still easily exhausted).

Modern JavaScript tooling — webpack, Vite, Jest, nodemon, Rollup, esbuild, Parcel, and any tool using chokidar or watchpack — watches every file in your project tree for changes. A typical project with node_modules contains 50,000 to 200,000 files. Watching even a fraction of those exhausts the default inotify limit instantly.

Platform clarification: This variant is Linux-only. macOS uses FSEvents (a different kernel API with no comparable per-user watch limit) so this error does not occur on macOS regardless of project size. Windows uses ReadDirectoryChangesW and also does not have this limit. If you see ENOSPC on macOS or Windows, it is always the disk-full variant.

Diagnose the inotify limit

# Check the current inotify watch limit
cat /proc/sys/fs/inotify/max_user_watches

# Count how many inotify watches are currently active (all processes)
find /proc/*/fd -lname anon_inode:inotify 2>/dev/null | wc -l

# See which processes are consuming inotify watches
find /proc/*/fd -lname anon_inode:inotify -printf '%hinfo/inotify\n' 2>/dev/null \
  | xargs grep -c '^inotify' 2>/dev/null \
  | awk -F/ '{print $3, $NF}' \
  | sort -k2 -rn | head -10

Fix A-1 – Raise fs.inotify.max_user_watches (permanent)

This is the primary fix. It persists across reboots and takes effect immediately.

Debian, Ubuntu, and most Linux distributions

# Permanent fix — appends to /etc/sysctl.conf and reloads immediately
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Verify the new value
cat /proc/sys/fs/inotify/max_user_watches
# Expected output: 524288

Arch Linux and systemd-based distributions

# Write to a drop-in file in /etc/sysctl.d/ instead
echo fs.inotify.max_user_watches=524288 | sudo tee /etc/sysctl.d/40-max-user-watches.conf
sudo sysctl --system

# Verify
cat /proc/sys/fs/inotify/max_user_watches

Temporary fix (resets after reboot)

# Effective immediately, no reboot required, but does not survive reboot
sudo sysctl fs.inotify.max_user_watches=524288
Why 524288? That is 512 × 1024 — a round number large enough to cover the largest monorepos. Each inotify watch consumes approximately 1 KB of kernel memory, so 524288 watches use roughly 512 MB in the worst case. On a modern Linux system with several GB of RAM this is completely safe.

Fix A-2 – Exclude node_modules from file watching

Excluding node_modules from your watcher config can reduce the watch count from 100,000+ files down to a few hundred, often eliminating the problem without needing to raise the sysctl limit. This should be done regardless of whether you hit the limit — watching node_modules is wasteful and slows down the watcher.

webpack (webpack.config.js)

// CJS — webpack.config.js
module.exports = {
  // ...
  watchOptions: {
    // Ignore node_modules — saves thousands of inotify watches
    ignored: /node_modules/,
    // Alternatively, use a glob array:
    // ignored: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
    aggregateTimeout: 300,
  },
};

Vite (vite.config.js / vite.config.ts)

// ESM — vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    watch: {
      // Exclude directories from inotify watching
      ignored: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
    },
  },
});

Jest (jest.config.js)

// jest.config.js
module.exports = {
  watchPathIgnorePatterns: [
    '/node_modules/',
    '/dist/',
    '/build/',
    '/.git/',
  ],
};

nodemon (nodemon.json or package.json)

// nodemon.json
{
  "watch": ["src"],
  "ignore": ["node_modules", "dist", ".git", "*.test.js"],
  "ext": "js,ts,json"
}

// Or inline in package.json:
// "nodemonConfig": { "watch": ["src"], "ignore": ["node_modules"] }

chokidar directly

// CJS
const chokidar = require('chokidar');

const watcher = chokidar.watch('./src', {
  // Ignore dotfiles and node_modules
  ignored: /(^|[/\\])(\.|node_modules)/,
  persistent: true,
  depth: 10,
});

watcher.on('change', (filePath) => console.log(`Changed: ${filePath}`));

// Handle ENOSPC gracefully and fall back to polling
watcher.on('error', (error) => {
  if (error.code === 'ENOSPC') {
    console.error('inotify limit hit — switching to polling mode');
    watcher.close();
    const pollingWatcher = chokidar.watch('./src', {
      ignored: /(^|[/\\])(\.|node_modules)/,
      usePolling: true,
      interval: 1000,
    });
    pollingWatcher.on('change', (filePath) => console.log(`Changed: ${filePath}`));
  }
});

Fix A-3 – Switch to polling mode as a quick workaround

Polling periodically checks file modification times instead of using inotify watch slots. It avoids the inotify limit entirely but consumes more CPU. Use it as an immediate workaround while you apply the permanent sysctl fix.

# For webpack/Create React App via watchpack:
WATCHPACK_POLLING=true npm start
WATCHPACK_POLLING=true npm run dev

# For chokidar-based tools (nodemon, Parcel, Storybook):
CHOKIDAR_USEPOLLING=true npm run dev
CHOKIDAR_USEPOLLING=true nodemon src/index.js

# For nodemon specifically:
nodemon --legacy-watch src/index.js

# Combine both for maximum compatibility:
WATCHPACK_POLLING=true CHOKIDAR_USEPOLLING=true npm run dev

Fix A-4 – Docker containers and WSL

Docker containers share the host kernel. The fs.inotify.max_user_watches value is a host-kernel setting — you cannot override it inside a Dockerfile or container. You must set it on the host machine.

# On the Docker host (not inside the container):
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Then restart your containers — they will inherit the new limit
docker-compose down && docker-compose up

For development containers where you cannot change the host, use polling via environment variables in docker-compose.yml:

# docker-compose.yml
services:
  app:
    build: .
    environment:
      # Bypass inotify entirely — use polling instead
      - CHOKIDAR_USEPOLLING=true
      - WATCHPACK_POLLING=true
      - CHOKIDAR_INTERVAL=1000   # polling interval in ms
    volumes:
      - .:/app
      - /app/node_modules        # anonymous volume prevents host node_modules from being watched

For WSL 2 (Windows Subsystem for Linux):

# Inside WSL 2 terminal:
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# If sysctl -p fails in WSL 2, restart WSL from PowerShell:
# wsl --shutdown
# wsl

Fix A-5 – GitHub Actions and GitLab CI (inotify variant)

CI runners run on Linux. If your build runs a dev server or a watcher (e.g., Storybook, Cypress with hot reload, or jest --watch), you may hit the inotify limit. Add a step before your build to raise it.

# .github/workflows/build.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Increase inotify watch limit
        run: |
          echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
          sudo sysctl -p

      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run build
# .gitlab-ci.yml
build:
  script:
    - echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
    - sudo sysctl -p
    - npm ci
    - npm run build
---

Root Cause B – Disk Space Exhausted

When the filesystem has no free blocks left, any operation that writes data — file writes, directory creation, pipe writes — throws ENOSPC: no space left on device. This is most common during npm install (which extracts hundreds of packages to disk), build processes that produce large artifacts, and in Docker containers where the overlay2 storage driver accumulates image layers.

The key differentiator from the inotify variant is err.syscall: disk-full errors always have syscall: 'write', 'mkdir', or 'open' — never 'watch'.

Fix B-1 – Diagnose disk usage

# Check free space on all mounted filesystems
df -h

# Sample output when disk is full:
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda1        20G   20G     0 100% /            <-- FULL

# Check inode usage (can be full even if disk blocks are free)
df -i

# Find the largest directories in the current tree
du -sh */ 2>/dev/null | sort -hr | head -20

# Find the largest individual files
find . -type f -printf '%s %p\n' 2>/dev/null | sort -rn | head -20

# Check npm cache size
du -sh ~/.npm

Fix B-2 – Free npm and package manager cache

# Clean npm's download cache (safe to delete — npm re-downloads as needed)
npm cache clean --force

# Verify the cache is cleared
npm cache verify

# Remove node_modules and reinstall (also clears old/stale packages)
rm -rf node_modules
npm install

# yarn cache
yarn cache clean

# pnpm store
pnpm store prune

# Find and remove large or duplicate node_modules across a monorepo
npx npkill    # interactive UI to select node_modules directories to delete

Fix B-3 – Free Docker disk space

Docker's overlay2 storage driver accumulates image layers, build cache, stopped containers, and dangling images on the host filesystem. On CI runners this is a common cause of ENOSPC during a build.

# See a breakdown of Docker disk usage
docker system df

# Sample output:
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          12        3         8.2GB     6.1GB (74%)
# Containers      2         2         1.5GB     0B (0%)
# Build Cache     45        0         3.2GB     3.2GB

# Remove all unused images, stopped containers, and build cache
docker system prune -a

# Remove only dangling (untagged) images
docker image prune

# Remove build cache only (safe to run during active development)
docker builder prune -a

# Remove unused volumes
docker volume prune
# Dockerfile best practices to avoid overlay2 disk bloat
FROM node:20-alpine

WORKDIR /app

# Copy package files first for layer caching
COPY package*.json ./

# Install production dependencies only; clean in the same layer
RUN npm ci --omit=dev && npm cache clean --force

COPY . .

RUN npm run build

# Multi-stage build: copy only the built output to the final image
FROM node:20-alpine AS final
WORKDIR /app
COPY --from=0 /app/dist ./dist
COPY --from=0 /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

Fix B-4 – GitHub Actions disk space

GitHub Actions ubuntu-latest runners have approximately 14 GB of free disk space. Pre-installed tools (dotnet, Haskell GHC, Android SDK) can consume several gigabytes. Large node_modules trees (1–3 GB), Docker image caches, and build artifacts can exhaust the remaining space.

# .github/workflows/build.yml — free disk space before building
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Free disk space
        run: |
          # Remove pre-installed tools that your project does not need
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf /usr/local/share/boost
          sudo rm -rf "$AGENT_TOOLSDIRECTORY"
          df -h   # confirm freed space

      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'      # cache node_modules between runs
      - run: npm ci
      - run: npm run build

Fix B-5 – GitLab CI disk space

# .gitlab-ci.yml — clean Docker cache between jobs and set artifact expiry
variables:
  DOCKER_DRIVER: overlay2

build:
  stage: build
  before_script:
    - docker system prune -af   # clean stale Docker layers before build
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour    # prevent artifacts from accumulating on the runner

Fix B-6 – Inode exhaustion

A filesystem can run out of inodes (directory entries) even when disk blocks are free. This happens when a huge number of tiny files are created — for example, deeply nested node_modules or a log-generation bug that creates millions of small files. The error message is identical to the disk-full variant.

# Check inode usage
df -i

# Sample output showing inode exhaustion:
# Filesystem     Inodes  IUsed  IFree IUse% Mounted on
# /dev/sda1      655360 655360      0  100% /         <-- inodes full

# Find directories with the most files (likely culprits)
find . -xdev -printf '%h\n' 2>/dev/null | sort | uniq -c | sort -rn | head -20

# Clean up log files, temp files, or duplicate node_modules
find . -name "*.log" -type f -delete
find . -name ".cache" -type d -exec rm -rf {} + 2>/dev/null || true

Fix B-7 – tmpfs /tmp too small

Some Linux systems (and Docker containers) mount /tmp as a tmpfs (in-memory filesystem) with a fixed size quota. npm writes temporary files to /tmp during install. If /tmp is full — even if the main disk has space — you get ENOSPC.

# Check if /tmp is mounted as tmpfs and how full it is
df -h /tmp
mount | grep tmpfs

# Redirect npm's tmp directory to a path with more space
npm config set tmp /var/tmp

# Or set via environment variable
export NPM_CONFIG_TMP=/var/tmp
npm install

Platform and Tool Reference

PlatformWatcher variant possible?Disk variant possible?Notes
Linux (native) Yes — inotify limit is the most common ENOSPC cause in dev Yes Fix watcher: sysctl fs.inotify.max_user_watches=524288. Fix disk: df -h + cleanup.
macOS No — macOS uses FSEvents, no per-user watch limit exists Yes ENOSPC on macOS is always disk-full. Check Disk Utility or df -h.
Windows No — uses ReadDirectoryChangesW, no inotify equivalent Yes (rare) ENOSPC on Windows is disk-full. Check disk usage in Explorer.
Docker (Linux host) Yes — containers inherit host inotify limit Yes — overlay2 layers fill the host disk Set sysctl on host. Use CHOKIDAR_USEPOLLING=true if host is immutable. Run docker system prune -a.
WSL 2 Yes — WSL 2 runs a real Linux kernel with inotify Yes Set sysctl inside WSL. Restart WSL with wsl --shutdown if needed.
GitHub Actions (ubuntu-latest) Yes — standard Linux runner Yes — 14 GB disk, easily consumed by large builds Add sysctl step for watcher. Remove pre-installed tools for disk space.
GitLab CI (shared runners) Yes — Linux runners Yes — smaller disk than GitHub Actions on shared runners Use docker system prune before build. Set artifact expiry.

Safe Watcher Patterns in Node.js Code

Detect and handle ENOSPC in fs.watch

// CJS
const fs = require('fs');

function watchWithFallback(targetPath, onChange) {
  try {
    const watcher = fs.watch(targetPath, { recursive: true }, (event, filename) => {
      onChange(event, filename);
    });

    watcher.on('error', (err) => {
      if (err.code === 'ENOSPC') {
        console.error(
          'ENOSPC: inotify watch limit reached. ' +
          'Fix: sudo sysctl fs.inotify.max_user_watches=524288'
        );
        // Fall back to polling
        watchWithPolling(targetPath, onChange);
      } else {
        throw err;
      }
    });

    return watcher;
  } catch (err) {
    if (err.code === 'ENOSPC') {
      console.error('ENOSPC on watch setup — falling back to polling');
      return watchWithPolling(targetPath, onChange);
    }
    throw err;
  }
}

function watchWithPolling(targetPath, onChange) {
  const chokidar = require('chokidar');
  return chokidar.watch(targetPath, {
    usePolling: true,
    interval: 1000,
    ignored: /node_modules/,
  }).on('change', (filePath) => onChange('change', filePath));
}

const watcher = watchWithFallback('./src', (event, filename) => {
  console.log(`${event}: ${filename}`);
});

Handle ENOSPC during file writes

// ESM
import { promises as fs } from 'fs';
import path from 'path';

async function writeFileSafe(filePath, content) {
  try {
    await fs.mkdir(path.dirname(filePath), { recursive: true });
    await fs.writeFile(filePath, content, 'utf8');
  } catch (err) {
    if (err.code === 'ENOSPC') {
      // Provide a clear actionable error message
      throw new Error(
        `ENOSPC: Disk full — cannot write to ${filePath}. ` +
        `Run 'df -h' to check disk usage and free space before retrying.`
      );
    }
    throw err;
  }
}

await writeFileSafe('./dist/bundle.js', bundleContent);

Debugging Checklist

  1. Read err.syscall: if it is 'watch' you have the inotify variant; if it is 'write', 'mkdir', or 'open' you have the disk variant.
  2. For the inotify variant: run cat /proc/sys/fs/inotify/max_user_watches — if the output is 8192 or 65535, raise it immediately with sudo sysctl fs.inotify.max_user_watches=524288.
  3. For the disk variant: run df -h to confirm the filesystem is at 100% usage and identify which mount is full.
  4. Run df -i to check inode exhaustion — a filesystem can run out of inodes even when disk blocks are free.
  5. Check whether node_modules is being watched — add ignored: /node_modules/ to your watcher config to eliminate thousands of unnecessary watch slots.
  6. If you are on Docker: remember inotify limits come from the host kernel; set sysctl on the host or use CHOKIDAR_USEPOLLING=true in the container environment.
  7. If you are on macOS or Windows and see ENOSPC: it is always disk-full — check disk space in your OS disk utility.
  8. In CI (GitHub Actions, GitLab): add the sysctl step for inotify; remove pre-installed tools or add a docker system prune step for disk.
  9. Run npm cache clean --force and check du -sh ~/.npm — the npm cache can grow to several gigabytes.
  10. As a quick test, try WATCHPACK_POLLING=true CHOKIDAR_USEPOLLING=true npm run dev — if the error disappears, the cause was definitely the inotify limit.
Do not use ENOSPC as a catch-all to silently ignore: The disk-full variant means real data is not being written. Swallowing the error in a catch block will cause silent data loss or corrupted build artifacts. Always surface the error with a clear message pointing to df -h, and let the operator fix the actual underlying resource problem.

Frequently Asked Questions

What is ENOSPC in Node.js?

ENOSPC is a POSIX error code meaning "Error NO SPaCe". In Node.js it appears as two distinct messages: Error: ENOSPC: no space left on device (disk full or inotify table full) and Error: ENOSPC: System limit for number of file watchers reached (Linux inotify limit exceeded). Both share code: 'ENOSPC' and errno: -28 but have different causes and fixes. Check err.syscall: 'watch' = inotify limit; 'write'/'mkdir' = disk full.

How do I fix Error: ENOSPC: System limit for number of file watchers reached?

This is a Linux inotify limit. The permanent fix is: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p. Then restart your dev server. Also exclude node_modules from watching in your tool's config (e.g. watchOptions.ignored: /node_modules/ in webpack, server.watch.ignored in Vite). For an immediate workaround without sudo access, set WATCHPACK_POLLING=true or CHOKIDAR_USEPOLLING=true.

How do I fix Error: ENOSPC: no space left on device during npm install?

Run df -h to confirm the disk is actually full. Then free space: npm cache clean --force removes the npm download cache (safe to delete). rm -rf node_modules removes installed packages (reinstall with npm install). On Docker hosts, docker system prune -a removes unused images and build cache. Use du -sh */ | sort -hr | head -20 to find the largest directories consuming space.

Why does ENOSPC happen with webpack, Vite, Jest, or nodemon?

These tools use chokidar or watchpack to monitor every file in your project for changes. On Linux, each watched path consumes one inotify watch slot — a kernel resource tracked separately from disk space. The default limit is 8192 watches on many distros, while a typical project with node_modules has 50,000–200,000 files. Raising fs.inotify.max_user_watches to 524288 and excluding node_modules from the watcher config permanently fixes the issue.

Does ENOSPC: System limit for number of file watchers reached happen on macOS or Windows?

No. The inotify watcher variant is Linux-only. macOS uses FSEvents (no comparable per-user watch limit) and Windows uses ReadDirectoryChangesW (no inotify equivalent). If you see ENOSPC on macOS or Windows it is always the disk-full variant — check df -h (macOS/Linux terminal) or Disk Utility / Windows Explorer on macOS/Windows.

How do I fix ENOSPC in a Docker container?

For the watcher variant: inotify limits are set by the host kernel, not the container. Run echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p on the host machine, then restart your containers. If you cannot modify the host, set CHOKIDAR_USEPOLLING=true and WATCHPACK_POLLING=true as environment variables in your docker-compose.yml. For the disk variant: run docker system prune -a on the host to remove unused images and build cache.

How do I fix ENOSPC on GitHub Actions or GitLab CI?

For the inotify watcher variant, add a step before your build: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p. For disk-full on GitHub Actions (14 GB runner disk), remove pre-installed tools first: sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/share/boost. For GitLab, use docker system prune -af in before_script and set short artifact expiry.

What is the difference between ENOSPC and EMFILE?

EMFILE ("too many open files") is a per-process file descriptor limit — raised with ulimit -n 65536. ENOSPC watcher variant is a Linux inotify watch-slot limit — raised with sysctl fs.inotify.max_user_watches. Both can surface during webpack/Vite startup but are separate resources with separate limits and separate fixes. EMFILE is about open file handles; ENOSPC watcher variant is about kernel inotify slots. You can hit both simultaneously if your project is large enough.

Why does ENOSPC happen in production but not locally?

Several reasons: (1) CI/CD runners have limited disk (GitHub Actions: ~14 GB) while developer laptops have hundreds of GB; (2) production servers or containers run Linux where the inotify watcher limit applies, while local development may be on macOS (FSEvents, no limit); (3) Docker build cache and old image layers accumulate on CI runners; (4) WSL 2 on Windows is a Linux environment where inotify limits do apply even though the host OS is Windows.

Related Errors