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.
#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: 1Diagnose 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.
# 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.
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 on the builder
[worker.oci]
max-parallelism = 4
defaultCgroupParent = ""
# or pass --ulimit per build as aboveKeep the build context small and deterministic
- A missing
.dockerignoresendsnode_modules,.git, and build output to the daemon, which is slow and can change layer hashes between environments. - A
COPYof 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
buildxand QEMU set up explicitly; a plaindocker buildon an ARM runner silently produces an ARM image.
How to prevent it
- Set a generous
--ulimit nofilefor descriptor-heavy builds. - Raise the daemon/builder default
nofileon runner images. - Lower build parallelism when a tool is descriptor-hungry.