146

Could someone explain the key differences between os.Exit() and panic() and how they are used in practice in Go?

Timur Fayzrakhmanov
  • 17,967
  • 20
  • 64
  • 95
  • 12
    Just a comment that will hopefully help in future Go code reading: In a lot of example code, `panic` is used to exit on error, purely due to the fact that it's easy to understand, and eliminates importing any other packages. This *doesn't mean it's good, or idiomatic practice!*. It's just a space saving device for example code. IRL reserve `panic` for *very* special situations. – Intermernet Feb 12 '15 at 09:12
  • 2
    Hm..good) especially "IRL" abbreviation - it's new for me :) Could you explain how panic eliminates package importing? – Timur Fayzrakhmanov Feb 12 '15 at 09:16
  • 7
    `panic` is a builtin. It's recommended (depending on circumstance) to use something like `os.Exit`, `log.Fatal` etc., which will return an error code to the OS (always recommended if possible). These all involve importing a package, and thus "clutter up" example code. Example code should always only be taken to demonstrate a solution to a specific problem. There may be other problems with the code, which make the code more complex if properly demonstrated, and therefore detract from the explanation of the answer given. YMMV. – Intermernet Feb 12 '15 at 09:21
  • 1
    Ok, got it!) Big thanks) I see there is yet another abbreviation for my vocabulary :) – Timur Fayzrakhmanov Feb 12 '15 at 09:40
  • 2
    NP, happy to help, and to increase your acronymic lexicon :-) – Intermernet Feb 12 '15 at 09:44
  • can't upvote @Intermernet 's comment enough! There is no production code case where a panic (or even os.Exit would ever be needed). A memory allocation failure is the only scenario for a panic. And os.Exit is just lazy - wait for your go-routines to complete! – colm.anseo Mar 12 '19 at 20:13

3 Answers3

128

First of all, whenever you have a "how it is used in practice" question, a good way to start is to search the Go source code (or any big enough Go code base, really), and the package docs for answers.

Now, os.Exit and panic are quite different. panic is used when the program, or its part, has reached an unrecoverable state.

When panic is called, including implicitly for run-time errors such as indexing a slice out of bounds or failing a type assertion, it immediately stops execution of the current function and begins unwinding the stack of the goroutine, running any deferred functions along the way. If that unwinding reaches the top of the goroutine's stack, the program dies.

os.Exit is used when you need to abort the program immediately, with no possibility of recovery or running a deferred clean-up statement, and also return an error code (that other programs can use to report what happened). This is useful in tests, when you already know that after this one test fails, the other will fail as well, so you might as well just exit now. This can also be used when your program has done everything it needed to do, and now just needs to exit, i.e. after printing a help message.

Most of the time you won't use panic (you should return an error instead), and you almost never need os.Exit outside of some cases in tests and for quick program termination.

Ainar-G
  • 34,563
  • 13
  • 93
  • 119
  • 19
    "This is useful in tests, when you already know that after this one test fails, the other will fail as well…" This smells of a testing anti-pattern of dependent tests. In a well-written test suite, each test is independent; the outcome of any given test should never determine the outcome of any other test. – gotgenes Oct 30 '16 at 18:51
  • 3
    @gotgenes Not necessarily. If I have a test that a certain function returns a non-nil struct, and that test fails, then I can expect that all the tests that examine the values of the struct are going to fail, too. It's the code that's dependent, not the tests. (That said, I wouldn't use `exit` in that case, I'd just expect a big stack of failed assertions.) – David Moles Jan 02 '19 at 22:59
113

First of all, os.Exit() can be used to exit the program normally without an error, and panic not, so that's one key distinction. Another is that panic somewhere can be caught and ignored or logged using recover.

But if we're talking about an erroneous exit code, let's say:

Use panic when something goes horribly wrong, probably a programmer error that should have been caught before going to production. This is why it prints the stack.

Use os.Exit(errorCode) or something like that if you want to:

  1. control the exit code of the program for scripting purposes.

  2. want an orderly exit on an error that is expected (e.g user input error).

So basically panic is for you, a bad exit code is for your user.

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
  • 24
    "So basically panic is for you, a bad exit code is for your user." <- Awesome tip – psousa Sep 17 '17 at 17:24
  • 1
    Could we say that panic() is somehow related to the usual assert() call in plain C? Well.. I know I always remove asserting call before pushing to production, I only enable them when testing a new feature. What I am saying is that most of time I use assert() to verify invariants that I guess must hold true in my code. Do you see the same usage for panic() ? :-) – yves Baumes Mar 26 '18 at 15:20
  • Shouldn't we mention the key difference that panic generates a stack trace and os.Exit() does not? – MattG Mar 01 '23 at 23:26
17

The key differences are:

  1. os.Exit skips the execution of deferred function.
  2. With os.Exit, you can specify the exit code.
  3. panic is terminating while os.Exit is not. (Seems other answers do not mention this.)

If you need to execute the deferred function, you have no choice but panic. (On the other hand, if you want to skip execution of deferred function, use os.Exit.)

If a non-void function is defined in such a way:

  1. the function contains a lot of branches
  2. all branches are terminated with return or panic

Then you cannot replace panic with os.Exit otherwise the compiler will refuse to compile the program, saying "missing return at end of function". (Go is very dumb here, even log.Panic does not terminate a function.)

Under other conditions:

  1. Use panic when something really wired happens, e.g. programming logic error.
  2. Use os.Exit when you want an immediate exit, with specified exit code.
weakish
  • 28,682
  • 5
  • 48
  • 60