Aller au contenu

Debug des workflows GitHub Actions

Mise à jour :

Votre workflow CI échoue. Vous regardez les logs… et vous ne comprenez rien. Ou pire : le workflow ne se déclenche même pas, sans aucun message d’erreur. Comment savoir ce qui ne va pas ?

Ce guide vous donne les techniques de détective pour comprendre ce qui se passe dans vos workflows GitHub Actions et résoudre les problèmes efficacement.

Pourquoi le debug est difficile ?

Contrairement au code local que vous pouvez exécuter pas à pas avec un débogueur, les workflows GitHub Actions s’exécutent sur des machines distantes auxquelles vous n’avez pas accès direct.

Les défis spécifiques :

DéfiConséquence
Exécution distantePas de console.log en temps réel
Environnement éphémèreLa VM disparaît après le run
Logs limitésPar défaut, seuls les messages standards sont visibles
Pas de breakpointsImpossible de mettre le workflow en pause

Les trois types de problèmes

Avant de debugger, identifiez le type de problème :

🔴 Le workflow ne se déclenche pas

Le workflow existe mais rien ne se passe quand vous poussez du code.

🟠 Le workflow échoue

Le workflow démarre mais un ou plusieurs jobs échouent.

🟡 Le workflow est trop lent

Le workflow fonctionne mais prend beaucoup trop de temps.

Chaque type de problème nécessite une approche différente.


Problème 1 : Le workflow ne se déclenche pas

C’est souvent le plus frustrant : vous poussez du code, mais rien ne se passe dans l’onglet Actions.

Étape 1 : Vérifier que le fichier est au bon endroit

Le workflow doit être dans .github/workflows/ et avoir l’extension .yml ou .yaml.

Terminal window
# Vérifier la structure
ls -la .github/workflows/
# Vous devez voir vos fichiers de workflow
# ci.yml deploy.yml etc.

Erreur courante : le fichier est dans .github/workflow/ (sans le “s”) ou dans un autre dossier.

Étape 2 : Vérifier la syntaxe YAML

Une erreur de syntaxe empêche GitHub de charger le workflow. Utilisez actionlint pour valider :

Terminal window
# Installer actionlint
brew install actionlint
# Valider tous les workflows
actionlint
# Valider un fichier spécifique
actionlint .github/workflows/ci.yml

Erreurs courantes :

# ❌ Mauvaise indentation (2 espaces attendus)
jobs:
build: # 1 espace au lieu de 2
runs-on: ubuntu-latest
# ❌ Guillemets manquants autour des caractères spéciaux
on:
push:
branches:
- feature/* # Le * doit être entre guillemets : "feature/*"
# ❌ Deux-points manquant
jobs:
build
runs-on: ubuntu-latest # Erreur : "build" sans ":"

Étape 3 : Vérifier les filtres de déclenchement

Votre workflow peut être configuré pour ne réagir qu’à certains événements ou certaines branches.

# Ce workflow ne se déclenche que sur main
on:
push:
branches:
- main # Si vous êtes sur develop, rien ne se passe !
# Ce workflow ne se déclenche que si des fichiers .py changent
on:
push:
paths:
- '**/*.py' # Un changement dans package.json est ignoré

Comment vérifier ?

  1. Regardez la section on: de votre workflow
  2. Comparez avec la branche/l’événement que vous testez
  3. Vérifiez les filtres paths: et paths-ignore:

Étape 4 : Vérifier l’onglet Actions

Parfois le workflow est désactivé ou en attente d’approbation :

  1. Allez dans l’onglet Actions de votre repository
  2. Regardez la liste des workflows à gauche
  3. Si le workflow n’apparaît pas → erreur de syntaxe
  4. Si le workflow apparaît en gris → il est désactivé (cliquez pour activer)
  5. Si vous voyez “Workflows require approval” → vous devez approuver

Étape 5 : Vérifier les événements spéciaux

Certains événements ont des comportements particuliers :

ÉvénementPiège courant
pull_requestNe se déclenche pas sur les PRs de forks (pour les secrets)
pull_request_targetSe déclenche sur le repo cible, pas le fork
schedulePeut être retardé si GitHub est surchargé
workflow_dispatchDoit être déclenché manuellement via l’interface

Problème 2 : Le workflow échoue

Le workflow démarre mais un step échoue. Voici comment trouver la cause.

Comprendre la structure des logs

Quand vous cliquez sur un run échoué, vous voyez une hiérarchie :

Run (ensemble du workflow)
└── Job (ex: build, test, deploy)
└── Step 1: Checkout code ✅
└── Step 2: Setup Node.js ✅
└── Step 3: Install dependencies ✅
└── Step 4: Run tests ❌ ← Le problème est ici
└── Step 5: Upload coverage (skipped)

Cliquez sur le step qui a échoué pour voir les détails.

Activer les logs de debug

Par défaut, GitHub n’affiche que les messages standards. Pour voir plus de détails, activez le mode debug.

Méthode 1 : Re-run avec debug

  1. Allez sur le run échoué
  2. Cliquez sur Re-run all jobs (menu en haut à droite)
  3. Cochez Enable debug logging
  4. Relancez

Méthode 2 : Variables d’environnement

Ajoutez ces variables à votre workflow :

name: CI
on: push
env:
# Active les logs détaillés du runner (la machine qui exécute)
ACTIONS_RUNNER_DEBUG: true
# Active les logs détaillés de chaque step
ACTIONS_STEP_DEBUG: true
jobs:
build:
runs-on: ubuntu-latest
steps:
# ...

Utiliser les commandes de workflow

GitHub Actions reconnaît des commandes spéciales dans les logs. Utilisez-les pour créer des messages visibles :

- name: Diagnostic
run: |
# Message de debug (visible seulement en mode debug)
echo "::debug::Variable PATH = $PATH"
# Notice (information visible dans les logs)
echo "::notice::Compilation réussie en 45 secondes"
# Warning (triangle jaune dans l'interface)
echo "::warning::La dépendance lodash est obsolète"
# Error (croix rouge, fait échouer le step)
echo "::error::Fichier de configuration manquant"

Résultat dans l’interface :

  • ::debug:: → Visible uniquement avec ACTIONS_STEP_DEBUG: true
  • ::notice:: → Annotation bleue dans le résumé du run
  • ::warning:: → Annotation jaune, n’échoue pas le workflow
  • ::error:: → Annotation rouge, fait échouer le step

Inspecter les contexts

Les contexts (github, env, secrets, etc.) contiennent les informations disponibles pendant l’exécution. Affichez-les pour comprendre l’état :

- name: Afficher le contexte GitHub
run: |
echo "Repository: ${{ github.repository }}"
echo "Branche: ${{ github.ref }}"
echo "Commit: ${{ github.sha }}"
echo "Événement: ${{ github.event_name }}"
echo "Acteur: ${{ github.actor }}"

Pour tout voir d’un coup (utile en debug) :

- name: Dump tous les contexts
env:
# On passe par une variable pour éviter les problèmes d'échappement
ALL_CONTEXTS: |
github: ${{ toJSON(github) }}
env: ${{ toJSON(env) }}
job: ${{ toJSON(job) }}
steps: ${{ toJSON(steps) }}
run: echo "$ALL_CONTEXTS"

Vérifier si un secret existe

Les secrets sont masqués dans les logs (remplacés par ***). Pour vérifier qu’un secret est bien configuré sans l’exposer :

- name: Vérifier les secrets
run: |
if [ -n "${{ secrets.NPM_TOKEN }}" ]; then
echo "✅ NPM_TOKEN est configuré"
else
echo "❌ NPM_TOKEN est vide ou non configuré"
exit 1
fi

Garder des preuves en cas d’échec

Quand un test échoue, les fichiers de log sont perdus avec la VM. Configurez un upload automatique :

- name: Exécuter les tests
run: npm test
- name: Sauvegarder les logs en cas d'échec
if: failure() # Ne s'exécute que si le step précédent a échoué
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: debug-logs-${{ github.run_id }}
path: |
logs/
coverage/
npm-debug.log
test-results/
retention-days: 5 # Garde les logs 5 jours

Les artifacts sont téléchargeables depuis la page du run.

Continuer malgré une erreur

Parfois vous voulez voir ce qui se passe après une erreur :

- name: Step qui peut échouer
id: risky-step
run: ./script-instable.sh
continue-on-error: true # Le workflow continue même si ce step échoue
- name: Analyser le résultat
run: |
echo "Résultat du step précédent: ${{ steps.risky-step.outcome }}"
# outcome = 'success' ou 'failure'
if [ "${{ steps.risky-step.outcome }}" == "failure" ]; then
echo "Le script a échoué, mais on continue pour collecter des infos"
fi

Problème 3 : Le workflow est trop lent

Votre workflow fonctionne, mais il prend 15 minutes au lieu de 3. Voici comment identifier les goulots d’étranglement.

Analyser la durée des steps

GitHub affiche la durée de chaque step dans l’interface. Cliquez sur un job pour voir le détail :

✓ Checkout (2s)
✓ Setup Node.js (5s)
✓ Install dependencies (4m 30s) ← Suspect !
✓ Run tests (1m 15s)
✓ Build (45s)

Dans cet exemple, l’installation des dépendances prend 4 minutes 30. C’est probablement un problème de cache.

Vérifier l’utilisation du cache

Cherchez ces messages dans les logs :

# ✅ Cache utilisé
Cache restored from key: npm-linux-abc123def456
# ❌ Cache non trouvé
Cache not found for input keys: npm-linux-xyz789

Si le cache n’est pas trouvé, vérifiez :

  1. La clé de cache correspond-elle à votre configuration ?
  2. Le cache a-t-il expiré (7 jours sans utilisation) ?
  3. Le cache a-t-il été invalidé par un changement de lockfile ?

Voir le guide Artifacts vs Cache pour optimiser.

Mesurer précisément avec des timestamps

Pour les opérations longues, ajoutez des mesures :

- name: Début du timer
run: echo "START_TIME=$(date +%s)" >> $GITHUB_ENV
- name: Opération longue
run: npm ci
- name: Fin du timer
run: |
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "::notice::Installation des dépendances : ${DURATION} secondes"

Identifier les problèmes réseau

Les téléchargements lents sont une cause fréquente de lenteur :

- name: Diagnostic réseau
run: |
echo "=== Test DNS ==="
time nslookup registry.npmjs.org
echo "=== Test de téléchargement ==="
time curl -s -o /dev/null -w "Temps: %{time_total}s\n" https://registry.npmjs.org

Limiter le temps d’exécution

Pour éviter les workflows qui tournent indéfiniment :

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30 # Le job entier ne peut pas dépasser 30 min
steps:
- name: Opération risquée
timeout-minutes: 5 # Ce step spécifique ne peut pas dépasser 5 min
run: ./script-potentiellement-long.sh

Messages d’erreur courants

”Resource not accessible by integration”

Error: Resource not accessible by integration

Ce que ça signifie : Le workflow n’a pas la permission de faire ce qu’il essaie de faire (commenter une PR, créer un label, etc.).

Solution : Ajouter les permissions nécessaires :

permissions:
contents: read # Lire le code
pull-requests: write # Commenter les PRs
issues: write # Créer/modifier les issues

“Workflow does not have permission”

Ce que ça signifie : Similaire au précédent, mais au niveau du repository.

Solution :

  1. Allez dans SettingsActionsGeneral
  2. Vérifiez “Workflow permissions”
  3. Sélectionnez “Read and write permissions” si nécessaire

”The workflow is not valid”

Ce que ça signifie : Erreur de syntaxe YAML.

Solution : Utilisez actionlint pour trouver l’erreur exacte.

”Context access might be invalid”

Ce que ça signifie : Vous essayez d’accéder à une propriété qui n’existe peut-être pas.

# ❌ Risqué si le step n'a pas d'outputs
- run: echo ${{ steps.build.outputs.version }}
# ✅ Plus sûr avec une valeur par défaut
- run: echo ${{ steps.build.outputs.version || 'unknown' }}

Workflow de diagnostic

Voici un workflow complet à déclencher manuellement pour diagnostiquer votre environnement :

name: Diagnostic
on:
workflow_dispatch: # Déclenchement manuel uniquement
permissions:
contents: read
jobs:
diagnostic:
runs-on: ubuntu-latest
steps:
- name: Informations système
run: |
echo "=== Système d'exploitation ==="
uname -a
cat /etc/os-release
echo "=== Ressources ==="
echo "CPU: $(nproc) cores"
free -h
df -h
echo "=== Outils installés ==="
echo "Node: $(node --version 2>/dev/null || echo 'non installé')"
echo "Python: $(python3 --version 2>/dev/null || echo 'non installé')"
echo "Docker: $(docker --version 2>/dev/null || echo 'non installé')"
echo "Git: $(git --version)"
- name: Contexte GitHub Actions
run: |
echo "Repository: ${{ github.repository }}"
echo "Branche/Tag: ${{ github.ref }}"
echo "Commit SHA: ${{ github.sha }}"
echo "Acteur: ${{ github.actor }}"
echo "Événement: ${{ github.event_name }}"
echo "Run ID: ${{ github.run_id }}"
echo "Run Number: ${{ github.run_number }}"
- name: Test réseau
run: |
echo "=== DNS ==="
nslookup github.com
echo "=== Connectivité ==="
curl -s -o /dev/null -w "GitHub API: %{http_code}\n" https://api.github.com
curl -s -o /dev/null -w "npm Registry: %{http_code}\n" https://registry.npmjs.org
curl -s -o /dev/null -w "PyPI: %{http_code}\n" https://pypi.org
- name: Variables d'environnement
run: |
echo "=== Variables GitHub ==="
env | grep GITHUB_ | sort
echo "=== PATH ==="
echo $PATH | tr ':' '\n'

Pour l’exécuter : ActionsDiagnosticRun workflow.


Tester localement avec act

Plutôt que de pousser et attendre à chaque modification, utilisez act pour exécuter vos workflows sur votre machine.

Terminal window
# Installer act
brew install act
# Exécuter le workflow par défaut
act
# Exécuter un job spécifique
act -j build
# Mode verbeux pour le debug
act -v

Voir le guide complet act.


À retenir

Valider la syntaxe

Utilisez actionlint avant de pousser pour éviter les erreurs évidentes.

Activer le debug

Les variables ACTIONS_RUNNER_DEBUG et ACTIONS_STEP_DEBUG révèlent les détails cachés.

Sauvegarder les artifacts

Utilisez if: failure() pour uploader les logs quand ça échoue.

Tester localement

act vous fait gagner du temps en évitant les allers-retours avec GitHub.

Checklist de debug :

  1. ✅ Vérifier que le workflow est dans .github/workflows/
  2. ✅ Valider la syntaxe avec actionlint
  3. ✅ Vérifier les filtres de déclenchement (on:, branches:, paths:)
  4. ✅ Regarder l’onglet Actions (workflow désactivé ?)
  5. ✅ Activer les logs de debug si le problème persiste
  6. ✅ Inspecter les contexts pour comprendre l’état
  7. ✅ Sauvegarder les artifacts en cas d’échec

Liens utiles

  • act — Exécuter les workflows localement
  • actionlint — Valider la syntaxe des workflows