Skip to content
Latchkey

Docker Build "too many open files" - Raise the ulimit for the Builder in CI

A RUN step opened more file descriptors than the builder allows. The default nofile ulimit is too low for the tool (a large compile, a bundler, a test runner), so it fails with "too many open files".

What this error means

The build fails inside a RUN step with too many open files, EMFILE, or pipe: too many open files. The same command runs fine on a host with a higher descriptor limit.

docker build output
#11 8.42 Error: EMFILE: too many open files, open '/app/node_modules/.../index.js'
#11 ERROR: process "/bin/sh -c npm run build" did not complete successfully: exit code: 1

Diagnose it: build context, cache, or platform?

A Dockerfile that builds locally and fails in CI usually differs in one of three ways: the build context contains different files, the layer cache is cold or poisoned, or the runner architecture does not match what the base image provides.

Terminal
# what is actually being sent as build context (dockerignore applies)
docker build --no-cache --progress=plain -t probe . 2>&1 | head -40

# what platform are you on, and what does the base image support?
docker version --format '{{.Server.Arch}}'
docker buildx imagetools inspect <base-image> | grep -i platform

# prove it is not a cache artefact
docker build --no-cache .

Common causes

The nofile ulimit is too low for the tool

Compilers, bundlers, and watchers open many files at once. When the descriptor limit inherited by the build is small, they exhaust it and fail.

Inherited daemon default carried into the build

BuildKit runs steps under the daemon’s default ulimits. If the host daemon’s nofile default is low, every build step inherits that ceiling.

How to fix it

Raise the file-descriptor limit for the build

Pass a higher --ulimit nofile so the RUN step has more descriptors.

Terminal
docker build --ulimit nofile=65536:65536 -t myorg/api:1.4.2 .

Set the builder default ulimit (BuildKit)

For buildx/BuildKit, configure the builder’s default ulimits so every build gets the higher limit.

buildkitd.toml
# buildkitd.toml on the builder
[worker.oci]
  max-parallelism = 4
  defaultCgroupParent = ""
# or pass --ulimit per build as above

Keep the build context small and deterministic

  • A missing .dockerignore sends node_modules, .git, and build output to the daemon, which is slow and can change layer hashes between environments.
  • A COPY of a path that exists locally but is gitignored will fail in CI, because the runner only has what the checkout produced.
  • Multi-arch builds need buildx and QEMU set up explicitly; a plain docker build on an ARM runner silently produces an ARM image.

How to prevent it

  • Set a generous --ulimit nofile for descriptor-heavy builds.
  • Raise the daemon/builder default nofile on runner images.
  • Lower build parallelism when a tool is descriptor-hungry.

Frequently asked questions

What causes Docker build "too many open files"?
There are 2 common causes: the nofile ulimit is too low for the tool and inherited daemon default carried into the build. Compilers, bundlers, and watchers open many files at once.
How do I fix Docker build "too many open files"?
There are 2 fixes depending on which cause you have: raise the file-descriptor limit for the build and set the builder default ulimit (buildkit). Work through them in order, since the first is the most common.
What does Docker build "too many open files" actually mean?
The build fails inside a RUN step with too many open files, EMFILE, or pipe: too many open files.
How do I stop Docker build "too many open files" happening again?
Set a generous --ulimit nofile for descriptor-heavy builds. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card