Aller au contenu
Développement medium

La gestion des erreurs en Go

6 min de lecture

Go

En Go, une erreur est une valeur ordinaire qu'on renvoie et qu'on vérifie, pas une exception qu'on attrape. Ce style explicite est déroutant au début, mais c'est lui qui rend le flot d'erreurs visible et traçable. Ce guide vous apprend à renvoyer une erreur, à l'envelopper pour garder son contexte, et à réagir précisément avec errors.Is et errors.As. Public visé : vous connaissez les fonctions et les interfaces. Exemples testés sur Go 1.26.

  • Renvoyer et vérifier une erreur explicitement.
  • Envelopper une erreur avec fmt.Errorf et %w.
  • Comparer avec errors.Is et extraire avec errors.As.
  • Définir une erreur sentinelle et une erreur personnalisée.

error est une interface toute simple (un type qui a une méthode Error() string). La convention Go : une fonction qui peut échouer renvoie une erreur en dernier retour, et l'appelant la vérifie immédiatement.

f, err := os.Open("config.yaml")
if err != nil {
return err // on remonte l'erreur
}
defer f.Close()

Le motif if err != nil revient partout : c'est le prix de l'explicite. La règle d'or : ne jamais ignorer une erreur silencieusement. Un _ = faire() qui jette l'erreur est un bug en puissance.

Remonter une erreur brute perd le contexte : on sait qu'il y a eu une erreur, pas où ni pourquoi. fmt.Errorf avec le verbe %w enveloppe (wrap) l'erreur d'origine en ajoutant du contexte, tout en la gardant récupérable.

var ErrIntrouvable = errors.New("ressource introuvable") // erreur sentinelle
func charger(id int) error {
if id == 0 {
return fmt.Errorf("charger id=%d: %w", id, ErrIntrouvable)
}
return nil
}

Le message final devient charger id=0: ressource introuvable : on cumule le contexte de chaque niveau. Le %w (et non %v) est essentiel : il conserve un lien vers l'erreur enveloppée, exploitable par errors.Is.

Une fois les erreurs enveloppées, on veut réagir à une cause précise. Deux outils : errors.Is compare à une erreur cible ; errors.As extrait un type d'erreur concret, même à travers plusieurs couches de wrapping.

type ErrValidation struct{ Champ string }
func (e *ErrValidation) Error() string { return "champ invalide: " + e.Champ }
func main() {
err := charger(0)
fmt.Println(errors.Is(err, ErrIntrouvable)) // true, même enveloppée
err2 := fmt.Errorf("wrap: %w", &ErrValidation{Champ: "id"})
var ev *ErrValidation
if errors.As(err2, &ev) { // récupère le type concret
fmt.Println("champ en cause:", ev.Champ) // id
}
}

errors.Is(err, ErrIntrouvable) renvoie true même si l'erreur a été enveloppée plusieurs fois : il déroule la chaîne. errors.As fait de même mais remplit une variable du type cherché, pour accéder à ses champs (ev.Champ). C'est bien plus robuste que comparer des messages texte.

  • Une erreur sentinelle (var ErrX = errors.New(...)) suffit quand vous voulez juste distinguer un cas (introuvable, expiré). On la teste avec errors.Is.
  • Une erreur personnalisée (un type avec une méthode Error()) sert quand l'erreur porte des données (le champ fautif, un code HTTP). On l'extrait avec errors.As.

Choisissez la sentinelle par défaut, et le type personnalisé dès que l'appelant a besoin d'informations structurées sur l'erreur.

Un exercice de wrapping et de test d'erreur. Cherchez la solution avant d'ouvrir la réponse.

Écrivez une fonction normaliser(s string) (string, error) qui :

  • renvoie une erreur enveloppant une sentinelle ErrVide si la chaîne est vide (ou uniquement des espaces).
  • sinon renvoie la chaîne en minuscules et sans espaces autour.

Dans main, appelez-la avec " " et réagissez au cas vide avec errors.Is, puis avec " Bonjour " pour vérifier la normalisation.

Indice : strings.TrimSpace retire les espaces ; %w conserve le lien vers ErrVide.

  • En Go, une erreur est une valeur renvoyée en dernier et vérifiée avec if err != nil ; ne l'ignorez jamais en silence.
  • fmt.Errorf("... %w", err) enveloppe une erreur en ajoutant du contexte tout en gardant le lien.
  • errors.Is compare à une erreur cible à travers le wrapping ; errors.As extrait un type d'erreur concret.
  • Une erreur sentinelle distingue un cas ; une erreur personnalisée porte des données structurées.
  • Piloter le code par errors.Is/As est bien plus robuste que comparer des messages texte.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn