Recover And Where Is It Valid
Fast recall
Quick revision
Core answer
Practical understanding of Panic Vs Error.
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
Recover is the hatch in the middle of a panic. It only does something when called inside a deferred function during an active panic on the same goroutine: it stops the unwind, the deferred function returns normally, and the panic value is handed to you as the return of recover.
Called anywhere else — outside a defer, after the unwind finished, on a different goroutine — recover returns nil and does nothing. There is no 'check for panics' you can do proactively; you can only be the deferred function that catches one in flight.
The idiomatic use is exactly one: a package boundary. A library function that might panic internally (because of a bug or an intentional invariant check) wraps its body in a deferred recover so its callers see an error value instead of a crash. Anything more elaborate — recover as control flow — is fighting the language.
func runSafely(fn func()) {
defer func() {
if r := recover(); r != nil {
log.Printf("worker panic: %v", r) // recover ONLY inside defer
}
}()
fn()
}
// recover() outside a defer returns nil — never catches anythingRecover And Where Is It Valid
Direct Answer
recover() returns the panic value and stops the unwinding — but only inside a deferred function while a panic is in flight. Anywhere else it returns nil.
Deep Dive & Architecture
Why the defer-only restriction? Because recover works by intercepting the unwind, and the unwind only runs through deferred calls. There's no stack inspection at arbitrary points, no exception object you can query — the mechanism is literally: the runtime is walking out of your function, defer gave you a callback on the way out, and recover says 'stop here, hand me the reason.'
The goroutine restriction matters in practice: a deferred recover in goroutine A cannot catch a panic in goroutine B. Each goroutine unwinds its own stack, which means code that spawns goroutines must give each one its own recover at its own boundary — usually a small wrapper function:
func runSafely(fn func()) {
defer func() { if r := recover(); r != nil { log.Printf("worker panic: %v", r) } }()
fn()
}
Without that, any panic in a worker goroutine takes down the whole server, no matter how many recovers the parent function has.
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 Panic Vs Error, and when would you use it?
- When would you use Panic Vs Error in a real project?
- How would you compare Panic Vs Error with an alternative?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.