This BuildKit error occurs when Docker cannot export build cache to a registry or local storage. The most common cause is using the default docker driver, which doesn't support cache export. Fix it by switching to the docker-container driver or enabling the containerd image store.
The "error exporting cache: failed to export cache" message in Docker indicates that BuildKit's cache export mechanism has failed during an image build operation. This error typically appears when using the `--cache-to` flag with `docker buildx build` to export build cache layers to an external location like a container registry or local directory. BuildKit, Docker's modern build subsystem, supports exporting cache metadata and layers separately from the final image. This enables faster rebuilds by reusing previously computed layers. However, this advanced caching feature requires specific driver configurations that aren't available with Docker's default setup. The error can manifest in several forms: "cache export feature is currently not supported for docker driver", "failed to export cache: invalid incomplete links", or "error writing layer blob" messages. Each variant points to a different underlying cause, but they all relate to BuildKit's inability to complete the cache export phase of the build process.
The default docker driver doesn't support cache export. Create a new builder with the docker-container driver:
# Create a new builder with docker-container driver
docker buildx create --name mybuilder --driver docker-container --use
# Verify the builder is active
docker buildx ls
# Now run your build with cache export
docker buildx build --cache-to type=registry,ref=myregistry/myimage:cache \
--cache-from type=registry,ref=myregistry/myimage:cache \
-t myimage:latest .The docker-container driver runs BuildKit in a container, enabling full BuildKit features including cache export.
For GitHub Actions, add the official buildx setup action before your build step:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:latest
cache-from: type=gha
cache-to: type=gha,mode=maxThe setup-buildx-action automatically creates a builder with the docker-container driver.
Docker Desktop users can enable the containerd image store as an alternative to switching drivers:
1. Open Docker Desktop
2. Go to Settings > General
3. Enable Use containerd for pulling and storing images
4. Click Apply & Restart
Or configure it via ~/.docker/daemon.json:
{
"features": {
"containerd-snapshotter": true
}
}After enabling, the default docker driver will support cache export features.
Cache export to a registry requires push permissions. Ensure you're properly authenticated:
# Login to your registry
docker login myregistry.com
# For AWS ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <account>.dkr.ecr.us-east-1.amazonaws.com
# For Google Artifact Registry
gcloud auth configure-docker us-docker.pkg.dev
# Test push access with a small image
docker pull alpine
docker tag alpine myregistry.com/test:cache-test
docker push myregistry.com/test:cache-testIf push fails, check your registry credentials and repository permissions.
If registry cache export keeps failing, try inline cache which embeds cache metadata in the image itself:
# Build with inline cache (works with default driver)
docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t myimage:latest .
# Push the image (cache metadata included)
docker push myimage:latest
# Later builds can use this image as cache source
docker build --cache-from myimage:latest -t myimage:latest .Inline cache is less powerful than registry cache but more compatible. It works with the default docker driver and doesn't require separate cache storage.
The "invalid incomplete links" error occurs when the cache chain is corrupted. This often happens in multi-stage builds with similar COPY instructions:
# Add --chown to differentiate cache keys
FROM node:18 AS builder
WORKDIR /app
COPY --chown=node:node package*.json ./
RUN npm ci
COPY --chown=node:node . .
RUN npm run build
FROM node:18-slim
WORKDIR /app
# Use different ownership to create distinct cache entry
COPY --chown=root:root --from=builder /app/dist ./dist
COPY --chown=root:root --from=builder /app/node_modules ./node_modulesThis issue was fixed in BuildKit v0.8.0+. Update Docker Desktop or your BuildKit version:
# Check BuildKit version
docker buildx version
# Update builder to use latest BuildKit
docker buildx create --name newbuilder --driver docker-container \
--driver-opt image=moby/buildkit:latest --useIf cache export hangs (especially with multi-stage builds), try these workarounds:
# Use mode=min instead of mode=max to export less cache data
docker buildx build --cache-to type=registry,ref=myimage:cache,mode=min .
# Export cache for specific stages only
docker buildx build --target builder --cache-to type=local,dest=./cache .
# Set a timeout for the build
timeout 30m docker buildx build --cache-to type=registry,ref=myimage:cache .For persistent issues, disable cache export temporarily and investigate:
# Build without cache export to confirm the build itself works
docker buildx build -t myimage:latest .
# Then test cache export separately
docker buildx build --cache-to type=local,dest=./test-cache .If registry cache isn't working, use local filesystem cache:
# Export cache to local directory
docker buildx build \
--cache-to type=local,dest=./buildcache \
--cache-from type=local,src=./buildcache \
-t myimage:latest .For CI/CD, mount a persistent volume or use CI-specific cache:
# GitHub Actions with local cache
- name: Build with local cache
uses: docker/build-push-action@v5
with:
context: .
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
# Move cache to prevent unbounded growth
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cacheUnderstanding BuildKit cache types:
- inline: Embeds cache metadata in the image. Simple but limited - only caches the final stage.
- registry: Stores cache as a separate manifest in a registry. Full caching but requires push access.
- local: Stores cache on the filesystem. Good for local development and CI with persistent storage.
- gha (GitHub Actions): Uses GitHub's cache API. Convenient but has size limits (10GB per repo).
- s3: Stores cache in S3. Requires BuildKit v0.10+ and proper AWS credentials.
Cache mode explained:
- mode=min: Only exports layers for the final stage (default)
- mode=max: Exports all intermediate layers from all stages (slower but more cache hits)
Debugging cache export issues:
# Enable BuildKit debug output
BUILDKIT_PROGRESS=plain docker buildx build --cache-to type=registry,ref=img:cache .
# Check builder logs
docker logs buildx_buildkit_mybuilder0
# Inspect cache manifest in registry
docker manifest inspect myregistry/myimage:cacheMulti-platform cache considerations:
When building multi-platform images, cache export can be tricky. Consider separate cache references per platform:
docker buildx build --platform linux/amd64,linux/arm64 \
--cache-to type=registry,ref=myimage:cache \
--cache-from type=registry,ref=myimage:cache .Buildx driver comparison:
| Driver | Cache Export | Use Case |
|--------|--------------|----------|
| docker | Limited (inline only without containerd) | Simple local builds |
| docker-container | Full support | CI/CD, advanced caching |
| kubernetes | Full support | K8s-based CI |
| remote | Full support | Dedicated BuildKit servers |
Known issues and workarounds:
- BuildKit issue #1981: Cache fails every second build with docker driver. Solution: use docker-container driver.
- GitHub Actions cache can fill up (10GB limit). Use move cache step to prevent unbounded growth.
- Some registries don't support OCI manifests required for cache. Check registry compatibility.
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub