# Go Foutafhandeling in 2026: Patronen, Wrapping en Technische Interviewvragen > Uitgebreide gids over Go error handling: sentinel errors, error wrapping met fmt.Errorf, errors.Is/As en best practices voor technische interviews. - Published: 2026-06-15 - Updated: 2026-06-15 - Author: SharpSkill - Tags: go, error-handling, best-practices, interview - Reading time: 8 min --- --- Go foutafhandeling onderscheidt de taal van de meeste gangbare alternatieven. In plaats van exceptions en try/catch-blokken behandelt Go fouten als waarden—expliciet geretourneerd door functies en gecontroleerd bij elke aanroep. Deze weloverwogen ontwerpkeuze plaatst foutafhandeling op de voorgrond, waardoor foutpaden zichtbaar en testbaar worden. > **Foutwaarden, Geen Exceptions** > > Go kent geen exception-mechanisme. Elke functie die kan falen retourneert een error als laatste returnwaarde. Dit patroon maakt de kosten van het negeren van fouten zichtbaar op bronniveau—en maakt foutstromen triviaal testbaar. ## De Error Interface en Waarom Deze Belangrijk Is Het volledige Go error-systeem rust op een enkele interface gedefinieerd in de [standaardbibliotheek](https://pkg.go.dev/builtin#error): ```go // builtin.go type error interface { Error() string } ``` Elk type dat `Error() string` implementeert voldoet aan deze interface. Deze eenvoud stimuleert composabiliteit: fouten kunnen structs, wrappers of iets anders zijn, zolang ze een stringrepresentatie produceren. Een eenvoudig custom error type demonstreert het patroon: ```go // apperror.go type NotFoundError struct { Resource string ID string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%s with ID %s not found", e.Resource, e.ID) } ``` Deze `NotFoundError` bevat gestructureerde data. Aanroepers kunnen de resourcenaam of ID programmatisch extraheren in plaats van een string te parsen—een cruciaal voordeel bij het bouwen van HTTP API's of CLI-tools die fouten mappen naar specifieke responses. ## Sentinel Errors voor Bekende Condities Sentinel errors zijn package-level variabelen die specifieke, bekende foutcondities representeren. De standaardbibliotheek gebruikt dit patroon uitgebreid: `io.EOF`, `sql.ErrNoRows`, `os.ErrNotExist`. ```go // errors.go var ( ErrNotFound = errors.New("record not found") ErrUnauthorized = errors.New("unauthorized access") ErrConflict = errors.New("resource conflict") ) ``` Sentinel errors werken het beste wanneer de aanroeper alleen moet weten *wat* er is mislukt, niet *waarom* in detail. Ze signaleren een conditie zonder aanvullende context mee te geven. De Go-conventie is om ze te prefixen met `Err` en het bericht in kleine letters te houden zonder interpunctie, volgens de [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments#error-strings) richtlijn. > **Wanneer Sentinels Problematisch Worden** > > Het exporteren van sentinel errors creëert een publiek API-contract. Downstream packages zullen ze matchen met `errors.Is`, dus het hernoemen of verwijderen van een sentinel error is een breaking change. Gebruik ze spaarzaam—alleen voor condities waarop aanroepers daadwerkelijk moeten branchen. ## Error Wrapping met fmt.Errorf en de %w Verb Error wrapping, geïntroduceerd in Go 1.13, voegt context toe aan een error terwijl het origineel behouden blijft in een keten. De `%w` verb in `fmt.Errorf` creëert deze keten: ```go // repository.go func (r *UserRepo) FindByID(ctx context.Context, id string) (*User, error) { user, err := r.db.QueryContext(ctx, "SELECT * FROM users WHERE id = $1", id) if err != nil { return nil, fmt.Errorf("UserRepo.FindByID(%s): %w", id, err) } return user, nil } ``` De gewrapte error behoudt de volledige keten. Een aanroeper drie lagen hoger kan nog steeds de originele sentinel matchen of het originele type extraheren. Elke laag voegt context toe over *waar* de fout optrad zonder te verhullen *wat* er gebeurde. Een cruciaal onderscheid: `%w` wrapt (behoudt de keten), terwijl `%v` de error als string formatteert en de keten verbreekt. Gebruik `%v` bewust wanneer de originele error niet door de abstractiegrens heen mag lekken—bijvoorbeeld wanneer een repository een database driver error wrapt die service-laag code nooit zou moeten inspecteren. ## Fouten Inspecteren met errors.Is en errors.As Het `errors` package biedt twee functies voor het inspecteren van gewrapte error-ketens, ter vervanging van directe vergelijking en type assertion. `errors.Is` doorloopt de keten op zoek naar een specifieke error-waarde: ```go // handler.go func handleGetUser(w http.ResponseWriter, r *http.Request) { user, err := userService.GetByID(r.Context(), chi.URLParam(r, "id")) if errors.Is(err, ErrNotFound) { http.Error(w, "User not found", http.StatusNotFound) return } if err != nil { http.Error(w, "Internal error", http.StatusInternalServerError) return } json.NewEncoder(w).Encode(user) } ``` `errors.As` extraheert een specifiek error type uit de keten: ```go // middleware.go func errorMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if r := recover(); r != nil { http.Error(w, "Internal error", http.StatusInternalServerError) } }() next.ServeHTTP(w, r) }) } func mapErrorToHTTP(err error) int { var notFound *NotFoundError if errors.As(err, ¬Found) { return http.StatusNotFound } var validationErr *ValidationError if errors.As(err, &validationErr) { return http.StatusBadRequest } return http.StatusInternalServerError } ``` Het belangrijkste voordeel ten opzichte van type assertions: beide functies doorlopen de volledige gewrapte keten. Een `NotFoundError` die drie keer is gewrapt met `fmt.Errorf` en `%w` matcht nog steeds. ## Gestructureerde Foutafhandeling in Gelaagde Applicaties Productie Go-applicaties organiseren fouten typisch over drie lagen: domain errors definiëren business-level condities, service errors voegen operationele context toe, en handler of transport errors mappen ze naar externe responses. ```go // domain/errors.go type DomainError struct { Code string Message string Err error } func (e *DomainError) Error() string { if e.Err != nil { return fmt.Sprintf("%s: %s: %v", e.Code, e.Message, e.Err) } return fmt.Sprintf("%s: %s", e.Code, e.Message) } func (e *DomainError) Unwrap() error { return e.Err } ``` De `Unwrap` methode is wat `errors.Is` en `errors.As` door de keten laat werken. Elk custom error type dat een andere error wrapt dient deze te implementeren. De service-laag wrapt domain errors met operationele context: ```go // service/user.go func (s *UserService) Deactivate(ctx context.Context, userID string) error { user, err := s.repo.FindByID(ctx, userID) if err != nil { return fmt.Errorf("deactivating user %s: %w", userID, err) } if user.Status == StatusInactive { return &DomainError{ Code: "ALREADY_INACTIVE", Message: fmt.Sprintf("user %s is already inactive", userID), } } return s.repo.UpdateStatus(ctx, userID, StatusInactive) } ``` ## Veelvoorkomende Interviewvragen over Go Foutafhandeling Technische interviews voor Go-posities testen regelmatig kennis van foutafhandeling. Deze vragen verschijnen frequent in screeningsrondes en worden uitgebreid behandeld in [Go error handling interviewvragen](/technologies/go/interview-questions/error-handling). **Waarom gebruikt Go error-waarden in plaats van exceptions?** Exceptions creëren onzichtbare control flow. Een functie die throwd draagt controle over naar een onbekende catch-locatie, mogelijk vele stack frames verderop. Go error-waarden maken elk foutpad expliciet in de functiesignatuur. De aanroeper beslist direct hoe de error af te handelen—retry, wrap, log of propageer. Dit elimineert het "verrassings-throw" probleem en maakt foutstromen leesbaar zonder tooling-ondersteuning. **Wat is het verschil tussen `%w` en `%v` in `fmt.Errorf`?** `%w` wrapt de error, waardoor de keten behouden blijft voor `errors.Is` en `errors.As`. `%v` formatteert de error als string, wat een nieuwe error produceert zonder ketenlink naar het origineel. Gebruik `%w` wanneer aanroepers de oorzaak moeten kunnen inspecteren; gebruik `%v` wanneer de oorzaak een implementatiedetail is dat niet door een abstractiegrens mag lekken. **Wanneer moet een functie een error retourneren vs. panic?** Panic is gereserveerd voor werkelijk onherstelbare situaties: programmeerfouten zoals index out of bounds, nil pointer dereferences, of geschonden invarianten die op een bug wijzen. Herstelbare fouten—netwerk timeouts, ontbrekende records, ongeldige input—retourneren errors. Een nuttige regel: als de conditie kan optreden tijdens normale operatie, retourneert het een error. Als het betekent dat het programma een bug heeft, panict het. **Hoe beïnvloedt de `Unwrap` methode error-keteninspectie?** Wanneer een custom error type `Unwrap() error` implementeert, volgen de `errors.Is` en `errors.As` functies die methode om de keten te doorlopen. Zonder `Unwrap` stopt de keten bij die error. Sinds Go 1.20 kunnen errors ook `Unwrap() []error` implementeren om meerdere gewrapte errors te retourneren, wat boomvormige error-ketens mogelijk maakt voor cases zoals het aggregeren van validatiefouten. ## Foutafhandelingspatronen om te Vermijden Verschillende anti-patronen verschijnen frequent in Go-codebases en tijdens code review sessies: **Fouten stilzwijgend negeren.** De blank identifier maakt dit syntactisch eenvoudig maar semantisch gevaarlijk: ```go // anti-pattern: silent error swallowing result, _ := riskyOperation() ``` Elke genegeerde error moet een weloverwogen, gedocumenteerde keuze zijn—nooit een shortcut. **Loggen en retourneren.** Dit patroon produceert dubbele log entries en verwart de aanroeper die de error ook afhandelt: ```go // anti-pattern: double handling if err != nil { log.Printf("operation failed: %v", err) return err } ``` De oplossing: of de error afhandelen (loggen, default retourneren, retry) *of* propageren. Niet beide. **String matching voor error classificatie.** Het controleren van `err.Error()` output met `strings.Contains` is fragiel. Error messages zijn geen API-contracten—ze kunnen veranderen tussen library versies. Gebruik `errors.Is` voor sentinel waarden en `errors.As` voor types. **Errors wrappen die goroutine-grenzen overschrijden zonder synchronisatie.** Wanneer meerdere goroutines concurrent errors produceren, gebruik `errgroup.Group` uit het `golang.org/x/sync` package of een vergelijkbaar synchronisatiemechanisme. ## Foutafhandeling met errgroup voor Concurrente Operaties Het `errgroup` package van golang.org/x/sync biedt een clean patroon voor het verzamelen van errors uit concurrente goroutines: ```go // batch.go func (s *OrderService) ProcessBatch(ctx context.Context, orderIDs []string) error { g, ctx := errgroup.WithContext(ctx) g.SetLimit(10) for _, id := range orderIDs { g.Go(func() error { if err := s.processOrder(ctx, id); err != nil { return fmt.Errorf("processing order %s: %w", id, err) } return nil }) } return g.Wait() } ``` `errgroup.WithContext` annuleert de afgeleide context wanneer een goroutine een error retourneert, wat de anderen signaleert om te stoppen. Dit voorkomt verspild werk en levert een enkele, gewrapte error aan de aanroeper. > **Go 1.24 en Foutafhandeling** > > Go 1.24 (februari 2025) heeft het errors package niet gewijzigd. De error handling API is stabiel sinds Go 1.13, met de Go 1.20 toevoeging van multi-error unwrapping via `Unwrap() []error`. Huidige voorstellen voor verbeterde error handling syntax blijven in discussie in de Go issue tracker. ## Conclusie - Behandel errors als waarden: retourneer ze expliciet en handel ze af bij elke aanroep in plaats van te vertrouwen op verborgen exception-mechanismen - Gebruik sentinel errors (`var ErrX = errors.New(...)`) alleen voor condities waarop aanroepers moeten branchen, en behandel ze als publieke API - Wrap errors met `fmt.Errorf` en `%w` om context toe te voegen terwijl de keten behouden blijft; gebruik `%v` om de keten bewust te verbreken bij abstractiegrenzen - Geef de voorkeur aan `errors.Is` boven `==` en `errors.As` boven type assertions—beide doorlopen de volledige gewrapte keten - Implementeer `Unwrap() error` op custom error types zodat keteninspectie correct werkt - Handel af of propageer—nooit beide. Een error loggen en retourneren produceert dubbele ruis - Gebruik `errgroup` voor concurrent error verzamelen in plaats van handmatige goroutine synchronisatie - Houd error messages in kleine letters zonder interpunctie, volgens Go-conventies --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/go/go-error-handling-patterns-wrapping-best-practices