Error Handling Scenario
Fast recall
Quick revision
Core answer
Whether you understand Error Handling Scenario beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The scenario with the wrapping chain:
func processOrder(orderID string) error {
user, err := loadUser(orderID)
if err != nil {
return fmt.Errorf("process order %s: load user: %w", orderID, err) // layer 1 context
}
charge, err := chargePayment(orderID, user)
if err != nil {
// payment failed — decide the ACTION, not just the return
if isRetryable(err) {
return fmt.Errorf("process order %s: charge: %w", orderID, err) // upstream retries
}
return fmt.Errorf("process order %s: charge: %w", orderID, err) // no retry for card declined
}
if err := publishQueue(orderID); err != nil {
log.Printf("queue publish failed for %s (non-fatal): %v", orderID, err)
// Queue failure: the ORDER is processed — don't fail the whole flow
// (outbox pattern: record locally, retry later)
}
return nil
}The decisions in this scenario:
- 1EACH layer wraps with ITS context (the order ID, the operation) — %w everywhere
- 2The caller sees the full chain: 'process order 123: charge: connection refused'
- 3Retryable vs terminal — checked and acted on at the layer with the knowledge
- 4Queue failure — the business outcome succeeded (payment charged); the notification is eventually-consistent (log + outbox), not a hard fail
The errors.As pattern at the top: if the API layer needs the specific error type: var apiErr APIError if errors.As(err, &apiErr) { if apiErr.Code == 429 { / backoff */ } }
The anti-pattern: wrapping everything as a generic 'something failed' — every layer adding context but nobody adding facts.
Error Handling Scenario
Direct Answer
Each layer's error wraps with what IT knows: DB: fmt.Errorf("load user %s: %w", id, err). External API: fmt.Errorf("charge order %s: %w", orderID, err). Queue: decide — retry or surface. Caller sees the chain: 'handle order: charge: connection refused'.
Deep Dive & Architecture
The wrap decision per layer, formalized:
- The DB layer knows WHAT it queried (the WHERE, the table, the ID)
- The service layer knows WHAT operation (charge order, process payment)
- The handler knows the HTTP context (the route, the request)
- Each adds its fact via %w; none re-wraps blindly
The action matrix (where errors get HANDLED, not just wrapped):
- Connection refused (DB/API): retry with backoff (the caller or middleware)
- Not found (DB): the caller's domain logic (404, empty result, skip)
- Card declined: terminal — no retry, user-facing
- Queue publish: outbox/local retry — the operation's success doesn't depend on the notification
The error-as-value design payoff: every branch above is a return + a wrap — the code reads linearly, each decision visible. No catch blocks separating the handling from the operation.
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- How would you compare Error Handling Scenario with an alternative?
- What is a common mistake when using Error Handling Scenario?
- When would you use Error Handling Scenario in a real project?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.