Exit with error code in go?

Error HandlingGoExit

Error Handling Problem Overview


What's the idiomatic way to exit a program with some error code?

The documentation for Exit says "The program terminates immediately; deferred functions are not run.", and log.Fatal just calls Exit. For things that aren't heinous errors, terminating the program without running deferred functions seems extreme.

Am I supposed to pass around some state that indicate that there's been an error, and then call Exit(1) at some point where I know that I can exit safely, with all deferred functions having been run?

Error Handling Solutions


Solution 1 - Error Handling

I do something along these lines in most of my real main packages, so that the return err convention is adopted as soon as possible, and has a proper termination:

func main() {
    if err := run(); err != nil {
        fmt.Fprintf(os.Stderr, "error: %v\n", err)
        os.Exit(1)
    }
}

func run() error {
    err := something()
    if err != nil {
        return err
    }
    // etc
}

Solution 2 - Error Handling

In python I commonly use pattern which converted to go looks like this:

func run() int {
	// here goes
	// the code

	return 1
}

func main() {
	os.Exit(run())
}

Solution 3 - Error Handling

I think the most clear way to do it is to set the exitCode at the top of main, then defer closing as the next step. That lets you change exitCode anywhere in main, and it's last value will be exited with:

package main

import (
    "fmt"
    "os"
)

func main() {
    exitCode := 0
    defer func() { os.Exit(exitCode) }()

    // Do whatever, including deferring more functions

    defer func() {
        fmt.Printf("Do some cleanup\n")
    }()

    func() {
        fmt.Printf("Do some work\n")
    }()

    // But let's say something went wrong
    exitCode = 1

    // Do even more work/cleanup if you want
 
    // At the end, os.Exit will be called with the last value of exitCode
}

Output:

Do some work
Do some cleanup

Program exited: status 1.

Go Playgroundhttps://play.golang.org/p/AMUR4m_A9Dw

Note that an important disadvantage of this is that you don't exit the process as soon as you set the error code.

Solution 4 - Error Handling

As mentioned by fas, you have func Exit(exitcode int) from the os package.

However, if you need the defered function to be applied, you always can use the defer keyword like this:

http://play.golang.org/p/U-hAS88Ug4

You perform all your operation, affect a error variable and at the very end, when everything is cleaned up, you can exit safely.

Otherwise, you could also use panic/recover: http://play.golang.org/p/903e76GnQ-

When you have an error, you panic, end you cleanup where you catch (recover) it.

Solution 5 - Error Handling

Yes, actually. The os package provides this.

package main

import "os"

func main() {
    os.Exit(1)
}

http://golang.org/pkg/os/#Exit

Edit: so it looks like you know of Exit. This article gives an overview of Panic which will let deferred functions run before returning. Using this in conjunction with an exit may be what you're looking for. http://blog.golang.org/defer-panic-and-recover

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondanView Question on Stackoverflow
Solution 1 - Error HandlingGustavo NiemeyerView Answer on Stackoverflow
Solution 2 - Error Handlinguser2424794View Answer on Stackoverflow
Solution 3 - Error HandlingBenView Answer on Stackoverflow
Solution 4 - Error HandlingcreackView Answer on Stackoverflow
Solution 5 - Error Handlingd1str0View Answer on Stackoverflow