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

Docker Error Guide: 'max depth exceeded' Image Layer Limit Failures

Fix Docker 'max depth exceeded': flatten oversized layer stacks, refactor RUN-heavy Dockerfiles, and rebuild base images that exceed the 125-layer limit.

  • #docker
  • #troubleshooting
  • #errors
  • #build

Exact Error Message

max depth exceeded appears when Docker tries to build, commit, or run an image whose layer stack has grown past the storage driver’s hard limit:

docker build -t app:latest .

...
 => ERROR [12/130] RUN apt-get install -y somepkg
------
failed to solve: max depth exceeded

It can also surface from docker commit or even at run time when the final image is assembled:

Error response from daemon: max depth exceeded

The number of layers, not their size, is the problem. A 200 MB image with 130 thin layers can hit this while a 4 GB image with 20 layers will not.

What the Error Means

The overlay2 storage driver mounts an image by stacking each layer as a lower directory in a single overlay mount. The Linux overlay filesystem has a practical limit on how many lower layers can be stacked, and Docker enforces a maximum image depth of 125 layers to stay within it. Every instruction in a Dockerfile that changes the filesystem — RUN, COPY, ADD — adds a layer, and those layers accumulate on top of whatever the base image already contributed. When the total crosses 125, Docker refuses to go deeper and reports max depth exceeded.

The error is almost always the result of a Dockerfile (or chain of base images) that creates one layer per tiny step, or of repeatedly committing/FROM-ing an already-deep image so each derived image inherits and extends the stack. The fix is to reduce the count of layers, not the disk usage.

Common Causes

  • Too many filesystem instructions. Dozens of separate RUN commands, each adding a layer.
  • Deep base image chains. A custom base built FROM another custom image, itself built FROM another, each adding layers that all carry forward.
  • Iterative docker commit workflows. Repeatedly committing a running container to build up an image, one layer at a time.
  • Loops generating layers. A build script or templated Dockerfile that emits many near-identical RUN lines.
  • Re-tagging and re-extending the same image repeatedly in a pipeline so depth compounds over time.

How to Reproduce the Error

Generate a Dockerfile with more than 125 trivial RUN layers on top of a base and build it:

{ echo 'FROM alpine:3.20'; for i in $(seq 1 130); do echo "RUN touch /f$i"; done; } > Dockerfile.deep
docker build -f Dockerfile.deep -t depthtest .
 => ERROR [126/130] RUN touch /f124
------
failed to solve: max depth exceeded

Remove Dockerfile.deep afterward.

Diagnostic Commands

Count the layers in an existing image to see how close to the limit you are:

docker image inspect app:latest --format '{{len .RootFS.Layers}}'

See the per-layer history (lines that changed the filesystem are layers):

docker history app:latest | head -40

Trace how deep the base chain is by inspecting the image you build FROM:

docker image inspect <base-image> --format '{{len .RootFS.Layers}}'

If the failure is at build time, read the BuildKit/daemon output for which step crossed the limit:

journalctl -u docker --since "10 min ago" | grep -i 'depth\|layer'

Step-by-Step Resolution

Cause: too many RUN instructions. Combine related commands into single RUN statements joined with &&, which collapses many layers into one:

RUN apt-get update \
 && apt-get install -y pkg-a pkg-b pkg-c \
 && rm -rf /var/lib/apt/lists/*

Each merged block is one layer instead of several. This alone usually drops a runaway Dockerfile well under the limit.

Cause: deep base chain. Flatten the lineage. Build the final image directly FROM an official slim base rather than stacking custom-on-custom. If you maintain shared bases, keep each one shallow and avoid chaining more than one level deep.

Cause: an already-deep image. Flatten an existing image by exporting and re-importing it, which collapses the entire history into a single layer:

docker run --name flat-tmp app:latest true
docker export flat-tmp | docker import - app:flat
docker rm flat-tmp

Note that import discards metadata like CMD/ENV, so re-add those in a tiny Dockerfile (FROM app:flat plus the instructions) — that still resets depth to a handful of layers.

Cause: iterative commits. Replace docker commit loops with a real multi-stage Dockerfile; multi-stage builds keep the final image’s depth low because only the last stage’s layers ship.

A worked example. A data team’s image had grown over months: every dependency change appended one more RUN pip install <pkg> line, and the Dockerfile was also built FROM last quarter’s already-deep internal base. The build finally failed at layer 126. Consolidating all the pip install lines into one RUN pip install -r requirements.txt cut roughly 40 layers, and rebasing onto python:3.12-slim instead of the internal chain removed another 60. Final depth dropped to 14 and builds succeeded. The reusable lesson: count layers (docker history) during code review, not after a failure.

Prevention and Best Practices

  • Merge related shell steps into single RUN blocks with && and clean up in the same layer.
  • Keep base-image chains shallow — prefer official slim/distroless bases over deep custom lineages.
  • Use multi-stage builds so only the final stage’s (few) layers ship in the image.
  • Track layer count in CI: fail the build if docker history shows the image approaching ~100 layers.
  • Avoid docker commit-driven image construction for anything maintained over time.

Frequently Asked Questions

What is the exact layer limit? Docker caps image depth at 125 layers for the overlay2 driver. The limit is on the count of filesystem layers, regardless of their size.

Do ENV, LABEL, or WORKDIR add layers? Metadata-only instructions don’t add filesystem layers in modern BuildKit, so they don’t count toward depth. RUN, COPY, and ADD do.

Will squashing help? Yes. Flattening (export/import, or a single squashed final stage) collapses many layers into one and resets depth, at the cost of losing layer-level caching and sharing.

Why did it work last month? You were under the limit then. Each added RUN/COPY pushed depth higher until one more instruction crossed 125. docker image inspect --format '{{len .RootFS.Layers}}' shows where you stand now.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

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.