N Should You Add Context With Errorf
Fast recall
Quick revision
Core answer
Practical understanding of Fmt Errorf.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
The judgment call in every error return. The test I apply: does my layer know something the error doesn't carry?
// the error says 'no such file' — my layer knows WHICH file
if err != nil {
return fmt.Errorf("read config %s: %w", path, err)
}
// the error says everything; my function is a thin pass-through
if err != nil {
return err
}The debugging reality drives it: the caller's question is always 'doing what, to which thing, when this failed?' os.ErrNotExist means one thing everywhere; your function knows it was the user's config, the payment retry, the migration step. Wrapping attaches that knowledge where the failure happened — the only place it's known accurately.
The counter-balance: every wrap adds reading. A stack of fmt.Errorf("failed: %w", ...) through five layers produces 'failed: failed: failed: disk full' — noise, no signal. Wrap when you have something to say, pass when you don't. The %w stays either way — a chain of meaningful wraps composes into a readable narrative: 'start server: load config: open /etc/app.conf: no such file or directory.'
N Should You Add Context With Errorf
Direct Answer
When your layer adds meaning the caller can't infer: the operation, the file, the request. If the error already says everything, pass it through.
Deep Dive & Architecture
The decision has a precise test, and it's about the READER's first question. When a caller sees an error from your function, the question is always 'what was happening?' — and the answer must be derivable from the error's chain. If your layer knows the answer and the chain doesn't carry it, wrap. If the chain already implies it, pass through.
The naming connection is the deep one: well-factored code needs LESS error context, because the function name carries it. loadConfig() returning a wrapped open-file error adds 'load config:' — but if the caller got that from calling loadConfig, they know that already. The wrap earns its line when the fact is otherwise invisible:
- a path the caller passed in (they know it — maybe skip)
- an INTERNAL path the caller never saw (they don't know it — wrap)
- which of several attempts failed (retry number, shard index — wrap)
- a value that matters to the failure (limit exceeded: N — wrap)
The read-aloud test: every segment should add a fact. 'failed, because: start server: listen :8080: address in use' — the 'failed because' segment never does.
Practical consequence: context belongs at the layer that HAS the fact, not the layer that noticed the failure. The deepest error knows the syscall; the top knows the operation; each layer adds its own fact and no one else's. That's how a well-wrapped chain reads like a debugging narrative without any layer guessing about others.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Fmt Errorf, and when would you use it?
- When would you use Fmt Errorf in a real project?
- What is a common mistake when using Fmt Errorf?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.