Callers Inspect A Custom Error
Fast recall
Quick revision
Core answer
Practical understanding of Custom Error Types Basics.
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
errors.As is the extraction tool:
var rateLimited *RateLimitError
if errors.As(err, &rateLimited) {
time.Sleep(rateLimited.RetryAfter)
retry()
}The pattern always has the same shape: declare a target of the error's type (pointer, because methods hang on pointers), pass its address to As, and As fills it if the chain contains a match. The wrap chain is traversed the same way Is traverses it — so intermediate layers wrapping with %w don't hide your type from the caller.
The pointer-vs-value detail matters: if your Error() method has a pointer receiver, the error stored in the chain is a *NotFoundError, so the target must be *NotFoundError — var target NotFoundError with &target makes As look for a value type and never match. This mismatch (value target for a pointer error) is the most common As bug, and it compiles cleanly — it just returns false forever.
As answers 'does this failure carry typed data, and give me that data.' Is answers 'is this failure this specific sentinel.' Together they cover the two reasons a caller inspects errors at all.
Callers Inspect A Custom Error
Direct Answer
var target *MyError; errors.As(err, &target) — walks the wrap chain, finds the first error of that type, copies it into target.
Deep Dive & Architecture
errors.As is a two-phase tool, and each phase has a failure mode worth knowing.
Phase 1 — the walk: As follows Unwrap edges (linear and []error branches) like Is. It succeeds when it finds an error assignable to the TYPE of the target pointer's pointee. The chain may hold your type once, wrapped three layers deep — As finds it through all of them.
Phase 2 — the assignment: the found error is assigned into *target — the caller's variable now holds the concrete struct with its fields, and the branch proceeds.
The failure modes:
- Pointer mismatch: error stored as *NotFoundError, target is NotFoundError (or vice versa) — no match ever, compiles clean. The fix is the ecosystem convention: always pointer on both sides.
- Multiple types in the chain: As returns the FIRST match — if two layers wrapped with different types and both match, you get the outer one. Rare, but worth knowing when debugging 'wrong field values.'
- The target must be a non-nil pointer to a type implementing error — As panics otherwise. The var pattern (
var e *MyErr; errors.As(err, &e)) is the safe shape.
When to use As vs Is: Is when the question is identity against a KNOWN value (a sentinel, a class representative). As when the question is about DATA — you need the fields. The practical ratio in real code: Is for control flow (is this retryable/cancelled/not-found), As when the handler uses failure details (log the name, sleep the duration, render the field).
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 Custom Error Types Basics, and when would you use it?
- How would you compare Custom Error Types Basics with an alternative?
- What is a common mistake when using Custom Error Types Basics?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.