Panic in Go

Panic in Go

In this tutorial, we are going to discuss panic in Go language. In Go, panic is a built-in function that stops the normal execution of the current goroutine and begins panicking.

Panic in Go
What is Panic?

In the Go language, Panic is similar to the exception. This is meant to exit from a program in abnormal conditions. It can occur in a program in 2 ways

  1. Runtime error in the program
  2. By calling the panic function explicitly. This can be called by the programmer when the program cannot continue and it has to exit.
1. Runtime Error in the program

Runtime error in the program can happen in the below cases

  • Calling a function on a nil pointer
  • Out of bounds array access
  • Sending on a closed channel
  • Incorrect type assertion etc.

Let’s stop theory and see an example of runtime error caused by out of bounds array access.

package main

import "fmt"

func main() {
    names := []string{"Ashok", "Sai", "Rama", "Seetha"}
    print(names, 5)
}

func print(names []string, index int) {
    fmt.Println(names[index])
}

Output

panic: runtime error: index out of range [5] with length 4

goroutine 1 [running]: 
main.print(...) 
         /tmp/sandbox745973963/prog.go:11 
main.main() 
         /tmp/sandbox745973963/prog.go:7 +0x1d

Run in playground

In the above example, we have a slice of length 4, and we are trying to access slice at index 5 in the print function.

Out of bound access is not allowed, and it will create panic, as seen from the output. Notice that in the output, there are two things

  • The error message
  • Stack trace of where the panic happened

Also there are many more cases in which runtime error can happen in a program. I am not going to mention all of them but you get the idea

Calling the panic function explicitly

In some of the cases where the panic function can be called explicitly by the programmer like,

  • The function expected a valid argument, but instead, a nil argument was supplied. In such a case, the program cannot continue, and it will raise a panic for a nil argument passed
  • Any other scenario in which the program cannot continue. etc.

Let’s see an example.

package main

import "fmt"

func main() {
    names := []string{"Ashok", "Sai", "Rama", "Seetha"}
    checkAndPrint(names, 5)
}

func checkAndPrint(names []string, index int) {
    if index > (len(names) - 1) {
        panic("Out of bound access for slice")
    }
    fmt.Println(names[index])
}

Output

panic: Out of bound access for slice 
goroutine 1 [running]: 
main.checkAndPrint(0xc0000a2f38, 0x4, 0x4, 0x5)   
      /tmp/sandbox582099440/prog.go:12 +0xea
main.main() 
      /tmp/sandbox582099440/prog.go:7 +0xb5

Run in playground

In the above example, we have a function named checkAndPrint that accepts a slice as an argument and an index. Then it checks whether the index passed is greater than the length of slice minus 1.

If it is, then it is out-of-bounds access for the slice, so it panics. If not, then it prints the value at that index. Again notice that in the output, there are two things.

  • The error message
  • Stack trace of where the panic happened
Panic with defer

When the panic is raised in a function, then the execution of that function is stopped, and any deferred function will be executed.

In fact a deferred function of all the function calls in the stack will also be executed until all the functions have returned. At that time, the program will exit, and it will print the panic message.

So if a defer function is present, then it will be executed, and the control will be returned to the caller function, which will again execute its defer function if present, and the chain goes on until the program exists.

package main

import "fmt"

func main() {
    var name string
    defer print()
    if name == "" {
       panic("Panic with Defer")
    }
    fmt.Println("After panic")
}

func print() {
    fmt.Println("Welcome to waytoeasylearn")
}

Output

Welcome to waytoeasylearn 
panic: Panic with Defer 

goroutine 1 [running]: main.main() 
     /tmp/sandbox533301674/prog.go:9 +0x5b

Run in playground

In the above program, we have a defer function first, and then we manually create the panic. As you can see from the output, that defer function got executed as the below line is printed in the output.

Welcome to waytoeasylearn 

Now let’s understand what happens when it happens in a program. Imagine a function call from the main function to f1 function to f2 function.

main->f1->f2

Controlflow

Now let’s say that panic happens in function f2, then below will be the sequence of events that will be happening.

  • The execution of f2 will stop. Defer functions in f2 will be executed if present. Control will return to the caller, which is a function f1.
  • f1 function will behave similarly as if panic happened in that function and after that call will return to the caller, which is the main function. Note that if there are more functions in between then, the process will continue up the stack in a similar way
  • The main function will also behave as if panic happened in that function, and after that, the program will crash
  • Once the program crashes, it will print the panic message along with this stack trace.
package main

import "fmt"

func main() {
    f1()
}

func f1() {
    defer fmt.Println("Defer in function f1")
    f2()
    fmt.Println("After painc in function f1")
}

func f2() {
    var name string
    defer fmt.Println("Defer in function f2")
    if name == "" {
        panic("Panic with Defer")
    }
    fmt.Println("After painc in function f2")
}

Output

Defer in function f2
Defer in function f1
panic: Panic with Defer
goroutine 1 [running]:
main.f2()
    /tmp/sandbox580326332/prog.go:17 +0x95
main.f1()
    /tmp/sandbox580326332/prog.go:10 +0x96
main.main()
    /tmp/sandbox580326332/prog.go:6 +0x25

Run in playground

In the above program, panic happened in the f2 function like below.

panic("Panic with Defer")

and the defer function in f2 is called after that and it prints the below message

Defer in f2

Notice that as soon as the panic happens in the f2 function, its execution stops therefore below line if f2 never gets executed

fmt.Println("After painc in f2")

Control returns to f1, and it has a defer function. The defer gets executed, and it prints the below message.

Defer in f1

Control returns to the main function after that, and then the program crashes. The output prints the panic message along with the entire stack trace from main to f1 to f2.

That’s all about the Panic in Go language. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Go language.!!

Panic in Go
Scroll to top