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
Resumeré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 Nextcontinue au-delà de l'échec. Très bien pour « on journalise et on passe », dangereux si la ligne sautée était porteuse.Resume Etiquetteest le cheval de trait : il envoie le contrôle vers votreSortiePropre: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
- VBA On Error — Resume Next vs GoTo & pourquoi les macros cachent les bugs
- Objet Err en VBA — Number, Description & déclencher vos propres erreurs
- VBA Sub dans Excel — Procédures, appel & pourquoi votre macro n'est qu'un Sub
- VBA Boucle For dans Excel — 8 exemples concrets
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.
