Docker "failed to solve: invalid mount config" (cache id) in CI
A RUN --mount=type=cache accepts an id, target, sharing, and a few other keys. When the mount config is malformed - a missing target, an unknown key, or two mounts fighting over the same id with incompatible sharing - BuildKit rejects it with "invalid mount config".
What this error means
A build with a cache mount fails at the RUN --mount=type=cache step with failed to solve: invalid mount config, naming the bad option or duplicate id.
ERROR: failed to solve: invalid mount config: duplicate mount target "/root/.cache" with conflicting cache idDiagnose 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
A missing or malformed target
A cache mount with no target= (or a relative target) cannot be resolved to a path inside the build.
Two cache mounts colliding on one id
Two --mount=type=cache declarations sharing an id but using different sharing modes (shared vs locked vs private) conflict.
An unknown mount key
A typo like targt= or an option BuildKit does not recognize makes the whole mount config invalid.
How to fix it
Give each cache mount a valid target and id
- Always set an absolute
target=. - Use a distinct
id=per logical cache, and keep the sharing mode consistent for a given id.
RUN --mount=type=cache,id=npm,target=/root/.npm,sharing=locked \
npm ciResolve id and sharing conflicts
- If two steps mount the same cache, give them the same id and the same sharing mode.
- If they should be independent caches, give them different ids.
# both steps reuse the same Go build cache safely
RUN --mount=type=cache,id=gobuild,target=/root/.cache/go-build,sharing=locked go build ./...
RUN --mount=type=cache,id=gobuild,target=/root/.cache/go-build,sharing=locked go test ./...Keep 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
- Always declare an absolute
target=on cache mounts. - Keep one sharing mode per cache id across all mounts that use it.