What happens if a goroutine panics? Can the parent recover it?
Question 167MediumGo 1.22 to 1.25
A panic that no one recovers, in any goroutine, crashes the whole process and prints that goroutine's stack. recover works only inside a deferred function in the same goroutine that panicked. A parent cannot catch its child's panic:
func main() {
defer func() { fmt.Println("recovered?", recover()) }() // never sees it
go func() { panic("boom") }()
time.Sleep(time.Second)
}
// Output: panic: boom ... exit status 2
A common pattern in servers is a safe-go wrapper that turns the panic into an error or a log entry:
func safeGo(wg *sync.WaitGroup, errs chan<- error, fn func()) {
wg.Go(func() {
defer func() {
if r := recover(); r != nil {
errs <- fmt.Errorf("panic: %v\n%s", r, debug.Stack())
}
}()
fn()
})
}
Gotchas:
net/httprecovers panics in handlers, but not in goroutines the handlers start.errgroupdoes not turn a panic into an error returned byWait. Recover inside the function if you need that.- Fatal runtime errors, such as concurrent map writes, running out of memory, or stack overflow, cannot be recovered.
More on Goroutines & the Scheduler
- Q165Why doesn't Go expose goroutine IDs, and how do you "kill" a goroutine?
- Q166What happens when main returns while other goroutines are still running? What does this print?
- Q168What does this print? (Closure capture and the Go 1.22 loop variable change)
- Q169When does the Go runtime report "all goroutines are asleep - deadlock!" and when doesn't it?
- Q170Concurrency vs. parallelism in Go — can goroutines run in parallel with GOMAXPROCS=1?
- Q171What are the goroutine states and what transitions happen on a channel block?