Corriger l’erreur Docker Build « failed to compute cache key »
L’erreur Docker Build « failed to compute cache key » apparaît quand Docker (souvent via BuildKit) n’arrive pas à calculer une clé de cache pour une étape de build. Dit autrement : Docker tente de déterminer si une étape peut être réutilisée depuis le cache (pour accélérer le build), mais une des entrées nécessaires (fichiers du contexte, métadonnées, permissions, liens symboliques, accès à un chemin, etc.) est inaccessible, incohérente, ou non déterministe.
Ce tutoriel explique en profondeur :
- ce que signifie réellement cette erreur (côté BuildKit),
- les causes fréquentes (contexte,
.dockerignore, chemins, symlinks, permissions, montages, builds multi-étapes), - comment diagnostiquer avec des commandes réelles,
- comment corriger selon les scénarios,
- comment rendre vos builds reproductibles et cache-friendly.
1) Comprendre ce que Docker essaie de faire (BuildKit et cache key)
1.1 BuildKit calcule une clé à partir des entrées d’une étape
Avec BuildKit (activé par défaut sur beaucoup d’installations modernes), chaque instruction du Dockerfile (ex. COPY, RUN, ADD) est transformée en une opération. Pour décider si l’opération peut être récupérée depuis le cache, BuildKit calcule une clé basée sur :
- l’instruction elle-même (texte, arguments),
- l’image de base (digest),
- les fichiers utilisés (pour
COPY/ADD), - parfois des métadonnées (permissions, timestamps selon cas),
- l’état des couches précédentes.
Si BuildKit ne peut pas lire un fichier du contexte, ou si un chemin mentionné n’existe pas, ou si un lien symbolique pointe vers l’extérieur, le calcul échoue et vous obtenez :
failed to compute cache key- souvent accompagné d’un sous-message du type :
failed to walk ...lstat ...: no such file or directoryfailed to calculate checksum of ref ...failed to read dockerfilenot foundpermission denied
1.2 Pourquoi l’erreur apparaît parfois “au hasard”
Le cache dépend des fichiers réellement envoyés au daemon (le contexte). Si votre contexte change (fichier généré, symlink, permission), ou si votre .dockerignore exclut un fichier nécessaire, l’erreur peut apparaître selon la machine, le répertoire courant, ou l’ordre de génération des artefacts.
2) Reproduire et lire correctement l’erreur
2.1 Activer une sortie plus lisible (progress=plain)
Utilisez BuildKit et demandez une sortie “plain” :
DOCKER_BUILDKIT=1 docker build --progress=plain -t monimage:debug .
Si vous utilisez docker buildx :
docker buildx build --progress=plain -t monimage:debug .
2.2 Exemple typique
Vous pourriez voir quelque chose comme :
#7 [stage-0 3/6] COPY package.json package-lock.json ./
#7 ERROR: failed to compute cache key: failed to calculate checksum of ref ...: "/package-lock.json": not found
Ici, BuildKit veut checksummer package-lock.json (pour la clé de cache de COPY), mais il n’est pas présent dans le contexte (ou il est ignoré, ou le chemin est faux).
3) Cause n°1 : fichier manquant dans le contexte (chemin faux ou build lancé au mauvais endroit)
3.1 Vérifier le répertoire courant
Beaucoup de builds échouent simplement parce qu’on exécute docker build depuis le mauvais dossier.
- Votre
Dockerfileest dans./docker/Dockerfile - Votre code est à la racine
- Vous lancez
docker builddans./docker
Dans ce cas, le contexte . ne contient pas vos sources.
Solution : définir explicitement -f et le contexte :
docker build -f docker/Dockerfile -t monimage:latest .
Ici, le contexte est . (racine du projet), et le Dockerfile est ailleurs.
3.2 Vérifier les chemins dans COPY
Dans un Dockerfile, COPY lit depuis le contexte, pas depuis le système de fichiers de l’hôte au sens large.
Mauvais exemple :
COPY ../monfichier.txt /app/
BuildKit interdit généralement de sortir du contexte.
Correct : ajustez le contexte ou déplacez le fichier dans le contexte.
Si vous avez besoin d’un contexte différent :
docker build -f docker/Dockerfile -t monimage:latest ..
Mais attention : élargir le contexte peut envoyer énormément de fichiers (lent, fuite de secrets).
4) Cause n°2 : .dockerignore exclut un fichier nécessaire
4.1 Symptôme
Vous avez bien le fichier dans votre projet, mais Docker dit not found lors d’un COPY. Souvent c’est .dockerignore.
Exemple de .dockerignore trop agressif :
**/*.json
node_modules
dist
Puis votre Dockerfile :
COPY package.json package-lock.json ./
BuildKit ne voit pas ces fichiers, donc checksum impossible => failed to compute cache key.
4.2 Diagnostiquer : afficher le contexte réellement envoyé
Docker ne fournit pas directement “la liste finale”, mais vous pouvez :
- Vérifier la taille du contexte dans la sortie build (souvent affichée).
- Faire un test en construisant un tar du contexte (approche pratique).
Sur Linux/macOS, vous pouvez simuler l’archive de contexte avec tar en respectant .dockerignore est non trivial. Une méthode plus simple : temporairement renommer .dockerignore :
mv .dockerignore .dockerignore.bak
DOCKER_BUILDKIT=1 docker build --progress=plain -t test:noignore .
mv .dockerignore.bak .dockerignore
Si ça marche sans .dockerignore, vous avez trouvé.
4.3 Corriger proprement
Ajustez .dockerignore pour inclure explicitement ce qu’il faut. Par exemple :
**/*.json
!package.json
!package-lock.json
node_modules
dist
Ou mieux : évitez les patterns trop globaux.
5) Cause n°3 : liens symboliques (symlinks) cassés ou pointant hors contexte
5.1 Pourquoi ça casse la clé de cache
BuildKit “marche” le répertoire pour calculer des checksums. Un symlink :
- cassé (cible inexistante),
- ou pointant vers un chemin non accessible / hors contexte,
peut faire échouer le “walk” ou le calcul de checksum.
5.2 Diagnostiquer les symlinks
Sur Linux/macOS :
find . -type l -print
Trouver les symlinks cassés :
find . -type l ! -exec test -e {} \; -print
Voir où pointe un lien :
readlink -f chemin/du/lien # Linux
readlink chemin/du/lien # macOS (sans -f selon version)
5.3 Solutions
- Remplacer les symlinks par des fichiers réels dans le contexte.
- Éviter de
COPYun répertoire qui contient des symlinks vers l’extérieur. - Réorganiser le projet pour que tout ce qui est nécessaire soit dans le contexte.
6) Cause n°4 : permissions et fichiers illisibles (EACCES)
6.1 Symptôme
Vous voyez permission denied pendant le build, parfois enveloppé dans failed to compute cache key.
Exemples :
- fichiers appartenant à root sur votre machine,
- répertoires non lisibles,
- attributs spéciaux.
6.2 Diagnostiquer
Lister les permissions :
ls -la
Trouver des fichiers non lisibles :
find . -type f ! -readable -print
Trouver des dossiers non traversables :
find . -type d ! -executable -print
6.3 Corriger
Rendre lisible (selon politique de sécurité) :
chmod -R u+rwX,go+rX .
Ou corriger propriétaire :
sudo chown -R "$USER":"$USER" .
Attention : ne faites pas ça aveuglément dans des répertoires sensibles. Ciblez le sous-répertoire du projet.
7) Cause n°5 : chemins “générés” attendus mais non créés (build non déterministe)
7.1 Exemple courant : dist/ absent
Dockerfile :
COPY dist/ /app/dist/
Mais dist/ est généré par un build local et n’existe pas sur une machine fraîche (CI).
Résultat : checksum impossible => erreur.
7.2 Approches correctes
Option A : générer dist/ dans l’image (recommandé)
Exemple Node.js multi-étapes :
FROM node:20-alpine AS build
WORKDIR /src
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=build /src/dist ./dist
COPY --from=build /src/package.json ./package.json
CMD ["node", "dist/index.js"]
Ici, vous ne dépendez pas d’un artefact local.
Option B : s’assurer que dist/ existe avant le build
Dans un pipeline CI :
npm ci
npm run build
docker build -t monimage:latest .
Mais attention : vous envoyez potentiellement beaucoup de fichiers (et vous devez gérer .dockerignore).
8) Cause n°6 : confusion entre ADD et COPY, archives, URLs
ADD a des comportements supplémentaires (décompression d’archives locales, téléchargement d’URL). Cela peut introduire des effets de bord et compliquer le cache.
8.1 Recommandation
- Utilisez
COPYpour les fichiers locaux. - Utilisez
RUN curl/wgetpour télécharger, en pinant une version, un checksum, etc.
Exemple robuste :
RUN apk add --no-cache curl ca-certificates \
&& curl -fsSL -o /tmp/out.tar.gz https://example.com/out-1.2.3.tar.gz \
&& echo "abc123... /tmp/out.tar.gz" | sha256sum -c - \
&& tar -xzf /tmp/out.tar.gz -C /opt \
&& rm -f /tmp/out.tar.gz
9) Cause n°7 : Build context énorme, fichiers spéciaux, sockets, devices
Si vous faites docker build . à la racine de votre home ou d’un monorepo mal ignoré, vous pouvez inclure :
.git/énorme,node_modules/,- fichiers spéciaux (sockets, pipes),
- caches.
BuildKit peut échouer en essayant de lire des entrées non régulières.
9.1 Corriger : réduire le contexte avec .dockerignore
Exemple solide pour un projet Node :
.git
node_modules
dist
coverage
.DS_Store
*.log
.env
.env.*
Et dans le Dockerfile, copiez d’abord les manifests pour maximiser le cache :
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
10) Cause n°8 : erreurs dans un build multi-plateforme (buildx) et chemins relatifs
En build multi-plateforme (docker buildx build --platform linux/amd64,linux/arm64 ...), BuildKit est plus strict et l’environnement diffère.
10.1 Diagnostic
Affichez le builder et sa config :
docker buildx ls
docker buildx inspect --bootstrap
Essayez un build mono-plateforme pour isoler :
docker buildx build --platform linux/amd64 --progress=plain -t monimage:test .
10.2 Causes fréquentes
- scripts
RUNqui dépendent d’un binaire non dispo sur une arch, - téléchargements non déterministes,
- chemins supposés.
Même si l’erreur mentionne le cache key, la source peut être un fichier introuvable lors d’un COPY conditionnel (ou un COPY qui dépend d’un argument).
11) Méthode de diagnostic systématique (checklist)
Quand vous voyez failed to compute cache key, appliquez cette procédure :
11.1 Étape 1 : localiser l’instruction fautive
Relancez avec :
DOCKER_BUILDKIT=1 docker build --progress=plain --no-cache -t debug:no-cache .
Même si --no-cache désactive la réutilisation, BuildKit calcule encore des checksums pour COPY. La sortie “plain” vous dira quelle étape échoue.
11.2 Étape 2 : vérifier l’existence du chemin côté hôte (dans le contexte)
Si l’erreur mentionne "/chemin": not found, vérifiez :
ls -la chemin
Si c’est un fichier :
test -f chemin && echo OK || echo MANQUANT
Si c’est un dossier :
test -d chemin && echo OK || echo MANQUANT
11.3 Étape 3 : vérifier .dockerignore
Cherchez des patterns qui matchent :
cat .dockerignore
Test rapide : renommer .dockerignore temporairement (voir section 4.2).
11.4 Étape 4 : symlinks et permissions
Symlinks cassés :
find . -type l ! -exec test -e {} \; -print
Fichiers non lisibles :
find . -type f ! -readable -print
11.5 Étape 5 : contexte correct et Dockerfile correct
Vérifiez la commande :
-fpointe vers le bon Dockerfile ?- le dernier argument (contexte) est correct ?
Exemple correct :
docker build -f docker/Dockerfile -t monimage:latest .
12) Corrections “patterns” avec exemples concrets
12.1 Pattern : COPY de fichiers optionnels
Docker ne gère pas “copier si existe” nativement. Si vous écrivez :
COPY package-lock.json ./
et que parfois vous n’avez pas de lockfile, ça casse.
Solutions :
- Standardiser : toujours committer
package-lock.json/poetry.lock/pnpm-lock.yaml. - Ou utiliser une stratégie par outil (ex. pnpm) et ajuster le Dockerfile.
Exemple pnpm :
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
12.2 Pattern : mauvais chemin de WORKDIR
Si vous faites :
WORKDIR /app
COPY . .
RUN cat ./scripts/build.sh
Mais scripts/build.sh est ignoré par .dockerignore, ou n’existe pas, l’erreur peut se produire au COPY ou plus tard.
Bon réflexe : copiez explicitement ce qui est nécessaire, par couches :
WORKDIR /app
COPY scripts/ ./scripts/
COPY src/ ./src/
COPY package.json package-lock.json ./
Cela rend aussi le cache plus stable.
12.3 Pattern : fichiers générés par Git (submodules) non initialisés
Si votre Dockerfile copie un sous-répertoire qui est un submodule Git, mais que le submodule n’est pas initialisé sur la machine/CI :
COPY vendor/ ./vendor/
Vous aurez “not found”.
Solution CI :
git submodule update --init --recursive
docker build -t monimage:latest .
13) Nettoyer et repartir sur une base saine (cache, builder, etc.)
Parfois, vous avez corrigé le contexte mais un builder BuildKit a un état incohérent (rare, mais possible). Vous pouvez nettoyer.
13.1 Nettoyer le cache BuildKit (prune)
docker builder prune
Plus agressif :
docker builder prune --all --force
Avec buildx :
docker buildx prune --all --force
13.2 Nettoyer images/containers inutilisés (attention)
docker system prune
Plus agressif (supprime aussi images non utilisées) :
docker system prune -a
14) Bonnes pratiques pour éviter l’erreur à l’avenir
14.1 Garder un contexte minimal
- Un
.dockerignorebien pensé - Ne pas builder depuis un répertoire trop haut (home, racine monorepo sans filtre)
14.2 Rendre les chemins explicites et stables
COPY package*.json ./(si vous êtes sûr que ça existe)- ou mieux : lister explicitement les fichiers requis
- éviter les
../dansCOPY
14.3 Préférer les builds multi-étapes
Ils évitent de dépendre d’artefacts locaux. Exemple générique :
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/app ./cmd/app
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/app /app
USER 65532:65532
ENTRYPOINT ["/app"]
14.4 Éviter les symlinks vers l’extérieur
Si vous utilisez des symlinks pour du dev local, envisagez :
- une étape de “vendorisation” (copie réelle) avant build,
- ou une structure de repo qui n’en a pas besoin.
15) Cas pratiques (diagnostic + correction)
15.1 Cas : COPY requirements.txt échoue en Python
Erreur :
failed to compute cache key: failed to calculate checksum ... "/requirements.txt": not found
Diagnostic :
ls -la requirements.txt
cat .dockerignore
pwd
Corrections possibles :
- Vous êtes dans le mauvais dossier : lancez depuis la racine du projet.
.dockerignoreignore*.txt: ajoutez!requirements.txt.
Dockerfile conseillé :
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
15.2 Cas : COPY . . échoue à cause d’un socket
Si votre projet contient un fichier spécial (ex. docker.sock ou socket de dev), BuildKit peut échouer.
Diagnostic :
find . -type s -print
find . -type p -print
Correction : ignorez-les :
**/*.sock
ou mieux, ignorez le répertoire qui les contient.
16) Résumé rapide des causes et remèdes
- Fichier manquant / mauvais chemin → vérifier commande
docker build, contexte, cheminsCOPY. .dockerignoretrop large → ajuster les patterns, inclure explicitement les fichiers requis.- Symlinks cassés / hors contexte → supprimer, remplacer, réorganiser.
- Permissions → rendre lisible/traversable, corriger ownership.
- Artefacts non générés → générer dans une étape de build (multi-stage) ou avant build.
- Contexte trop gros / fichiers spéciaux → réduire via
.dockerignore.
17) Commandes utiles (pense-bête)
# Build verbeux
DOCKER_BUILDKIT=1 docker build --progress=plain -t monimage:debug .
# Sans cache (pour isoler)
DOCKER_BUILDKIT=1 docker build --progress=plain --no-cache -t monimage:nocache .
# Lister symlinks
find . -type l -print
# Symlinks cassés
find . -type l ! -exec test -e {} \; -print
# Fichiers non lisibles
find . -type f ! -readable -print
# Dossiers non traversables
find . -type d ! -executable -print
# Nettoyage cache build
docker builder prune --all --force
docker buildx prune --all --force
Si vous collez ici :
- la ligne exacte de l’erreur (les 20–30 lignes autour),
- votre commande
docker build ..., - les extraits pertinents du
Dockerfileet.dockerignore,
je peux vous dire précisément quelle entrée empêche le calcul de la cache key et proposer la correction la plus propre.