Firstly, registering a delayed function for recovery should be the first line in the function, because since you do this last, it will not even be reached, because the line / code before defer already panicking, and therefore the delayed function is not registered, which restores the pan state.
So, change your do() function to the following:
func do() { defer func() { if err := recover(); err != nil { fmt.Println("Restored:", err) } }() str := "abc" fmt.Print(str[3]) }
Secondly: this alone will not make your code work, since you call wg.Defer() in a deferred function that will be executed only once main() ends - it never happens because you call wg.Wait() in main() . Thus, wg.Wait() expects wg.Wait() calls, but wg.Done() calls will not be made until wg.Wait() returns. This is a dead end.
You should call wg.Done() from the do() function, in the deferred function, something like this:
var wg sync.WaitGroup func do() { defer func() { if err := recover(); err != nil { fmt.Println(err) } wg.Done() }() str := "abc" fmt.Print(str[3]) } func main() { for i := 0; i < 1; i++ { wg.Add(1) go do() } wg.Wait() fmt.Println("This line should be printed after all those invocations fail.") }
Conclusion (try on the Go Playground ):
Restored: runtime error: index out of range This line should be printed after all those invocations fail.
This, of course, needed to move the wg variable to the global scope. Another option is to pass it to do() as an argument. If you decide to go this route, note that you need to pass a pointer to WaitGroup , otherwise only a copy will be passed ( WaitGroup is a type of struct ), and calling WaitGroup.Done() in the copy will not affect the original.
With passing WaitGroup to do() :
func do(wg *sync.WaitGroup) { defer func() { if err := recover(); err != nil { fmt.Println("Restored:", err) } wg.Done() }() str := "abc" fmt.Print(str[3]) } func main() { var wg sync.WaitGroup for i := 0; i < 1; i++ { wg.Add(1) go do(&wg) } wg.Wait() fmt.Println("This line should be printed after all those invocations fail.") }
The output is the same. Try this option on the Go Playground .