🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Gestion des erreurs VBA dans Excel — Le seul motif que toute macro fiable emploie

|

Gestion des erreurs VBA dans Excel — Le seul motif que toute macro fiable emploie

Testé sur : Excel 365 v2509 · Excel 2021 · Excel 2019 · dernière vérification le 08/06/2026

En bref — VBA n'a pas de try/catch. Une gestion des erreurs fiable tient en une seule forme que vous réutilisez dans chaque procédure qui compte : armer un gestionnaire en haut, faire le travail, faire passer chaque sortie — succès ou échec — par un point de nettoyage unique, puis quitter. Copiez ce modèle :

Sub TraiterRapport()
    On Error GoTo Gestionnaire
    Application.ScreenUpdating = False        ' état que l'on DOIT rétablir plus tard

    Dim ws As Worksheet
    Set ws = Sheets("Donnees")                ' toute erreur ici saute à Gestionnaire
    ws.Range("A1:A1000").Value = 0

SortiePropre:                                 ' L'UNIQUE sortie par laquelle passe tout chemin
    Application.ScreenUpdating = True         ' toujours rétabli, erreur ou non
    Exit Sub

Gestionnaire:
    MsgBox "Échec de TraiterRapport : " & Err.Description
    Resume SortiePropre                       ' on nettoie, puis on quitte
End Sub

Cette structure — On Error GoTo / travail / SortiePropre: / Exit Sub / Gestionnaire: / Resume SortiePropre — c'est toute la discipline. Le reste de ce guide explique pourquoi chaque ligne est là.

Le modèle mental : vous bâtissez à la main le try/finally que VBA ne vous donne pas

Des langages comme Python et C# ont try / except / finally. VBA n'a rien de tout cela. Ce qu'il vous donne à la place, ce sont trois primitives — On Error GoTo Etiquette, une étiquette et Resume — avec l'attente que vous les assembliez vous-même en la structure équivalente.

Faites la correspondance avec try/finally et ça cesse de paraître arbitraire :

try/catch/finally Équivalent VBA
try { On Error GoTo Gestionnaire
catch (e) { bloc Gestionnaire:, qui lit Err
finally { le bloc SortiePropre: que les deux chemins atteignent
throw Err.Raise

Dès que vous voyez le modèle comme un « try/finally manuel », la place de chaque ligne devient évidente au lieu d'apprise par cœur. La partie non négociable, c'est l'unique étiquette de nettoyage par laquelle passent à la fois le chemin du succès et celui de l'erreur.

La seule règle : Resume décide où vous allez après le gestionnaire — choisissez mal et vous bouclez ou vous fuyez

Dans un gestionnaire, vous avez trois façons de continuer, et choisir la mauvaise est le bug classique de gestion des erreurs VBA :

Resume              ' RÉEXÉCUTE la ligne exacte qui a échoué — sûr seulement si vous avez corrigé la cause
Resume Next         ' SAUTE la ligne fautive, continue avec celle d'après
Resume SortiePropre ' SAUTE à une étiquette — normalement votre sortie de nettoyage unique
  • Resume réessaie la ligne fautive. Ne l'utilisez que lorsque le gestionnaire a changé quelque chose qui permet à la réexécution de réussir (créé un dossier manquant, ouvert un classeur fermé). Utilisez-le à l'aveugle et vous obtenez une boucle infinie — échec, gestion, réessai, échec, à l'infini.
  • Resume Next continue au-delà de l'échec. Très bien pour « on journalise et on passe », dangereux si la ligne sautée était porteuse.
  • Resume Etiquette est le cheval de trait : il envoie le contrôle vers votre SortiePropre: pour que le nettoyage tourne toujours avant la fin de la procédure.

Un gestionnaire qui tombe en bout de bloc sans aucun Resume / Exit laisse l'erreur arrêter la macro de fait — décidez donc toujours la sortie explicitement.

La partie que tout le monde saute : le point de nettoyage unique est ce qui sauve votre fichier

Voici le mode de défaillance qui transforme un petit bug en ticket de support. Une macro règle un état global d'Excel pour la vitesse :

Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

…puis tombe en erreur avant de les rétablir. Excel est maintenant figé et ne recalcule plus, et l'utilisateur croit qu'Excel lui-même est cassé — bien après que votre macro a quitté. La même histoire vaut pour un descripteur de fichier ouvert (laissé verrouillé), un objet Set (jamais libéré), ou une feuille laissée non protégée.

La correction est structurelle, pas une affaire de code soigneux : placez chaque ligne « doit toujours s'exécuter » à une étiquette unique que le chemin normal et le gestionnaire atteignent tous deux, et faites que le gestionnaire Resume vers elle :

Sub ImporterFichier()
    Dim ff As Integer
    On Error GoTo Gestionnaire
    Application.ScreenUpdating = False
    ff = FreeFile
    Open "C:\Donnees\entree.csv" For Input As #ff
    ' ... on lit le fichier, ce qui peut exploser à mi-chemin ...

SortiePropre:
    If ff <> 0 Then Close #ff             ' fichier TOUJOURS fermé
    Application.ScreenUpdating = True      ' interface TOUJOURS rétablie
    Exit Sub
Gestionnaire:
    MsgBox "Échec de l'import : " & Err.Description
    Resume SortiePropre                   ' le chemin d'erreur passe aussi par le nettoyage
End Sub

Le succès tombe dans SortiePropre. L'échec saute à Gestionnaire, puis Resume SortiePropre. Les deux routes ferment le fichier et rétablissent l'interface. C'est votre finally.

Faire remonter les erreurs vers l'appelant (re-déclenchement)

Un assistant de bas niveau ne devrait généralement pas décider comment toute l'application réagit — il devrait nettoyer ses propres ressources et laisser l'appelant décider. Capturez l'erreur, rétablissez l'état, puis re-déclenchez :

Private Sub ChargerDonnees()
    On Error GoTo Gestionnaire
    ' ... travail qui peut échouer ...
    Exit Sub
Gestionnaire:
    Dim n As Long, d As String, s As String
    n = Err.Number: d = Err.Description: s = Err.Source   ' sauver avant que le nettoyage ne vide Err
    ' (nettoyage local ici)
    Err.Raise n, s, d                                     ' re-déclenche vers le gestionnaire de l'appelant
End Sub

Sauvegardez d'abord les valeurs d'Err — les instructions de nettoyage vident Err à votre insu. Ensuite, Err.Raise envoie l'erreur d'origine vers qui que ce soit qui a appelé ChargerDonnees, où un gestionnaire de haut niveau peut la journaliser une fois et montrer à l'utilisateur un seul message propre.

Un gestionnaire de journalisation centralisé

Pour tout ce que vous livrez, journalisez les erreurs quelque part de relisible plus tard, au lieu de compter sur l'utilisateur pour faire une capture du MsgBox :

Gestionnaire:
    JournaliserErreur "TraiterRapport", Err.Number, Err.Description
    Resume SortiePropre
End Sub

Private Sub JournaliserErreur(proc As String, num As Long, desc As String)
    Dim ff As Integer: ff = FreeFile
    Open ThisWorkbook.Path & "\journal_erreurs.txt" For Append As #ff
    Print #ff, Now & " | " & proc & " | " & num & " | " & desc
    Close #ff
End Sub

Quand On Error Resume Next est le bon outil

Toutes les situations ne réclament pas un gestionnaire. Pour une seule ligne dont l'échec est attendu et sans danger — sonder si un objet existe — un Resume Next étroit est plus net qu'une étiquette, à condition de vérifier Err.Number et de désarmer avec On Error GoTo 0 :

On Error Resume Next
Set ws = Sheets("Facultatif")
On Error GoTo 0
If ws Is Nothing Then Set ws = Sheets.Add   ' n'existait pas → on la crée

Le détail complet du « quand c'est sûr vs imprudent » est dans On Error : Resume Next vs GoTo.

L'avis tranché : la maturité ne se mesure pas au nombre de gestionnaires, mais à leur convergence

Vous pouvez saupoudrer On Error GoTo sur chaque procédure et écrire malgré tout des macros fragiles. Le signe de maturité en gestion des erreurs est plus étroit et plus tranchant : chaque procédure a-t-elle une sortie unique par laquelle passent tous les chemins, et où le nettoyage a lieu ? Si la réponse est non, une seule erreur en milieu de procédure laisse ScreenUpdating désactivé, le moteur de calcul en manuel et un fichier verrouillé — et votre utilisateur en veut à Excel, pas à votre code.

Donc mon critère pour « cette macro est prête pour la production » n'est pas la présence de gestionnaires. C'est : prenez n'importe quelle ligne, imaginez-la qui déclenche une erreur — le fichier se referme-t-il quand même et l'interface se rétablit-elle quand même ? Si oui, vous avez intériorisé le motif. Si non, plus d'instructions On Error ne vous sauveront pas ; un SortiePropre: le fera.

Erreurs fréquentes de gestion des erreurs (et la correction)

Symptôme Cause Correction
Excel « se fige » après une erreur de macro ScreenUpdating / Calculation jamais rétablis Les rétablir à un SortiePropre: vers lequel le gestionnaire fait Resume
Le fichier reste verrouillé / « déjà ouvert » Close / Set …= Nothing sauté sur le chemin d'erreur Mettre le nettoyage à la sortie unique que les deux chemins atteignent
Boucle infinie Resume réessaie une ligne dont la cause n'a pas été corrigée Utiliser Resume Next ou Resume Etiquette, pas un Resume nu
L'appelant n'apprend jamais l'échec L'assistant a avalé l'erreur avec un MsgBox Sauver Err, nettoyer, puis Err.Raise pour re-déclencher
Le journal affiche erreur 0 Err lu après que le nettoyage l'a vidé Copier Err.Number / Description avant de nettoyer
Le succès affiche aussi le message d'échec Pas de Exit Sub avant Gestionnaire: Mettre Exit Sub (ou tomber dans SortiePropre) avant l'étiquette

Quand le nettoyage pèse plus lourd que le travail — décrivez plutôt le travail

Reprenez ce modèle. La vraie tâche fait deux lignes ; le gestionnaire, l'étiquette de nettoyage, le Resume, la journalisation, le re-déclenchement sont les vingt autres. Ce ratio ne fait qu'empirer sur de vrais pipelines. ExcelMaster Agent vous laisse décrire le travail — « importe ces CSV, rapproche sur l'ID de commande, signale les écarts, envoie un e-mail à la compta » — en français courant, et le Python généré gère les échecs, rétablit l'état et sauvegarde votre classeur avant de toucher quoi que ce soit. Sans On Error, sans Resume, sans Excel figé. Essayer gratuitement →

Guides liés

FAQ

VBA a-t-il un try/catch ? Non. VBA n'a pas de try/catch/finally. Vous en construisez l'équivalent à partir de On Error GoTo Etiquette, d'une étiquette de gestionnaire, d'une étiquette de nettoyage unique et de Resume. Le modèle standard arme un gestionnaire en haut, fait passer chaque sortie par un point de nettoyage, puis quitte.

Quel est le meilleur motif de gestion des erreurs en VBA ? Armez On Error GoTo Gestionnaire, faites le travail, puis prévoyez une étiquette SortiePropre: où vous rétablissez l'état (ScreenUpdating, fichiers ouverts, objets) et faites Exit Sub. Le bloc Gestionnaire: lit Err, le journalise au besoin, et fait Resume SortiePropre. Le succès comme l'échec passent par le même nettoyage — c'est la clé.

Quelle différence entre Resume, Resume Next et Resume Etiquette ? Resume réexécute la ligne qui a échoué (sûr seulement si le gestionnaire a corrigé la cause, sinon vous obtenez une boucle infinie). Resume Next saute la ligne fautive et continue. Resume Etiquette saute à une étiquette — d'ordinaire votre sortie de nettoyage unique, pour que le nettoyage tourne toujours.

Comment garantir que le nettoyage s'exécute toujours après une erreur en VBA ? Placez chaque instruction « doit toujours s'exécuter » à une étiquette unique (p. ex. SortiePropre:) disposée de sorte que le chemin normal y tombe, et faites que le gestionnaire d'erreurs fasse Resume SortiePropre. Les deux chemins exécutent alors le nettoyage. C'est le substitut VBA d'un bloc finally.

Comment faire remonter une erreur d'un assistant vers la procédure appelante ? Dans le gestionnaire de l'assistant, sauvegardez Err.Number, Err.Description et Err.Source dans des variables, faites le nettoyage local éventuel, puis appelez Err.Raise avec ces valeurs sauvegardées. L'erreur remonte vers le gestionnaire On Error de l'appelant, où vous pouvez la journaliser une fois et montrer à l'utilisateur un seul message.