Skip to content
DevOps AI ToolKit
Newsletter
All guides
Docker with AI By James Joyner IV · · 9 min read Last reviewed Jul 2026

Docker Error Guide: 'too many open files' — Fix File Descriptor Limits

Quick answer

Fix 'too many open files' in Docker: raise nofile ulimits for the daemon and containers, lift the inotify watch ceiling, and stop descriptor leaks that crash busy containers.

  • #docker
  • #troubleshooting
  • #errors
  • #ulimits
Free toolkit

Stuck on this Docker with AI error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

too many open files is the kernel’s EMFILE/ENFILE error: a process tried to open a file, socket, or pipe but had already hit its file-descriptor limit. In containers this surfaces constantly because every socket, log file, and inotify watch counts against the limit, and the default per-process nofile cap is often far too low for a busy server. The literal error appears in application logs and daemon output like this:

accept tcp [::]:8080: accept4: too many open files

Node, Java, nginx, Elasticsearch, and file-watching dev servers are frequent victims. The variant that trips up developers uses inotify watches, which share the same class of limit:

Error: ENOSPC: System limit for number of file watchers reached

Symptoms

  • An application inside a container logs too many open files under load and starts rejecting connections.
  • nginx logs worker_connections exceed open file resource limit.
  • A dev server (webpack, Vite, nodemon) crashes on start with ENOSPC / System limit for number of file watchers reached.
  • The Docker daemon itself logs too many open files when running hundreds of containers.
  • docker build or docker-compose up fails intermittently on a host with many containers already running.

Common Root Causes

  • Low per-process nofile limit — the container inherits a small soft limit (often 1024) that a connection-heavy service exhausts almost immediately.
  • Daemon nofile too low — the dockerd process has its own limit; with many containers it runs out of descriptors for their sockets and log files.
  • File-descriptor leak in the app — sockets, files, or DB connections opened but never closed, so usage climbs until it hits the cap.
  • inotify watch exhaustion — file-watching tools exceed the host’s fs.inotify.max_user_watches (this is a host kernel setting, not a per-container ulimit).
  • High connection concurrency — a proxy or API server handling thousands of simultaneous sockets legitimately needs a high limit.
  • No limit set in Compose/run — relying on the host default instead of declaring ulimits for the workload.

Diagnostic Workflow

First confirm the limit the container is actually running with, and how close it is to the ceiling:

docker exec <container> sh -c 'ulimit -Sn; ulimit -Hn'    # soft and hard nofile
docker exec <container> sh -c 'ls /proc/1/fd | wc -l'      # FDs open by PID 1

Inspect the container’s configured ulimits and the daemon’s own limit:

docker inspect <container> --format '{{json .HostConfig.Ulimits}}'
cat /proc/$(pidof dockerd)/limits | grep 'open files'

Watch descriptor usage climb over time — a steady rise with flat load points to a leak:

watch -n5 "docker exec <container> sh -c 'ls /proc/1/fd | wc -l'"

For the inotify variant, check the host watch limit and current usage:

sysctl fs.inotify.max_user_watches
sysctl fs.file-nr        # allocated / free / max file handles system-wide

Read the daemon and system logs for the error origin:

journalctl -u docker --since '30 min ago' | grep -i 'open files\|emfile\|nofile'
docker logs <container> 2>&1 | grep -i 'too many open files\|enospc'

Example Root Cause Analysis

A Node.js API container began returning 500s under peak traffic, logging accept4: too many open files. docker exec <container> sh -c 'ulimit -Sn' reported 1024, and ls /proc/1/fd | wc -l sat right at ~1020 during peaks — the process was slamming into the default soft limit. But watch showed the count also stayed high for minutes after traffic dropped, which pointed at more than just concurrency. Inspecting the code confirmed outbound HTTP keep-alive sockets to a downstream service were never being released. The immediate mitigation was to raise the container limit with --ulimit nofile=65536:65536 so peak concurrency fit; the real fix was closing the leaked agent sockets so idle usage returned to baseline. Root cause: an FD leak amplified by an under-sized default nofile limit — both had to be addressed.

Prevention Best Practices

  • Declare ulimits explicitly for connection-heavy services rather than trusting the host default of 1024.
  • Set the daemon’s own limit high (LimitNOFILE in the docker.service systemd unit) on hosts that run many containers.
  • Load-test to find the real peak descriptor count and set the limit with generous headroom above it.
  • Treat a rising idle FD count as a leak signal in monitoring, not just an absolute threshold.
  • Raise fs.inotify.max_user_watches on the host for file-watching dev/build workloads; it cannot be fixed with a container ulimit.
  • Prefer connection pooling with proper release over opening a fresh socket per request.

Quick Command Reference

docker exec <container> sh -c 'ulimit -Sn; ulimit -Hn'     # current soft/hard nofile
docker exec <container> sh -c 'ls /proc/1/fd | wc -l'      # FDs held by the main process
docker inspect <c> --format '{{json .HostConfig.Ulimits}}' # configured limits
docker run --ulimit nofile=65536:65536 myimage             # raise per container
cat /proc/$(pidof dockerd)/limits | grep 'open files'      # daemon limit
sysctl fs.inotify.max_user_watches                         # host watch ceiling
sudo sysctl -w fs.inotify.max_user_watches=524288          # raise it (persist in sysctl.d)

Compose equivalent:

services:
  api:
    ulimits:
      nofile:
        soft: 65536
        hard: 65536

Conclusion

too many open files is a limit problem with two independent knobs and one trap. The knobs are the per-container nofile ulimit (set with --ulimit or Compose ulimits) and the daemon’s own LimitNOFILE; the trap is the inotify variant, whose ceiling is a host sysctl that no container ulimit can raise. Before you simply raise the number, check whether the descriptor count falls back down when load drops — if it does not, you have a leak, and a higher limit only delays the crash. Measure the real peak, set limits with headroom, and fix leaks at the source. More runtime and host-limit fixes are in the Docker guides.

Free download · 368-page PDF

Fixed it? Get 500 Docker with AI & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.