Go Gopher How to Go

The os package in Go provides the Exit function to immediately terminate the program with a given status code. Exit is typically used to indicate whether a program completed successfully or encountered an error. By convention, exit code 0 indicates success, while non-zero codes indicate various types of failures.

💡 Key Points

  • os.Exit(0) indicates successful program termination
  • Non-zero exit codes indicate errors or abnormal termination
  • Exit immediately terminates without running deferred functions
  • Use log.Fatal() to log and exit with status 1
  • panic() exits with status 2 if unrecovered
  • Exit codes can be checked by shell scripts and CI/CD systems
  • Prefer returning errors from main over calling Exit directly

Basic Exit Usage

Use os.Exit to terminate a program with a specific status code:

package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Starting program")
    
    // Exit with success code
    if true {
        fmt.Println("Operation successful")
        os.Exit(0)
    }
    
    // This will not execute
    fmt.Println("This won't print")
}
Output:
Starting program
Operation successful

Exit with Error Codes

Use different exit codes to indicate different types of failures:

package main

import (
    "fmt"
    "os"
)

func main() {
    args := os.Args
    
    if len(args) < 2 {
        fmt.Println("Error: missing required argument")
        os.Exit(1)
    }
    
    value := args[1]
    
    if value == "invalid" {
        fmt.Println("Error: invalid input")
        os.Exit(2)
    }
    
    fmt.Println("Processing:", value)
    os.Exit(0)
}
Output (no args):
Error: missing required argument
Exit code: 1

Exit vs Deferred Functions

Important: os.Exit does NOT run deferred functions:

package main

import (
    "fmt"
    "os"
)

func main() {
    defer fmt.Println("This deferred function will NOT run")
    
    fmt.Println("About to exit")
    os.Exit(1)
}
Output:
About to exit

Exit Code Conventions

Exit CodeMeaningUsage
0SuccessProgram completed successfully
1General errorCatchall for general errors
2MisuseMisuse of shell command or unrecovered panic
126Cannot executeCommand invoked cannot execute
127Command not foundCommand not found or path issue
128+nFatal error signalFatal error signal n (e.g., 130 = Ctrl+C)
130Terminated by Ctrl+CScript terminated by Control-C (SIGINT)
255Exit status out of rangeExit status out of range (0-255)

Exit Functions Comparison

FunctionExit CodeRuns DefersUse Case
os.Exit(0)0NoSuccessful termination
os. Exit(n)nNoError termination with code
log.Fatal()1NoLog error and exit
log.Fatalf()1NoLog formatted error and exit
log.Fatalln()1NoLog error with newline and exit
panic()2YesPanic (unrecovered exits with 2)
return from main0YesNormal function return

Exit Patterns

PatternCodeUse Case
Successful Exitos.Exit(0)Explicitly exit with success
Error Exitfmt.Fprintln(os.Stderr, err); os.Exit(1)Print error to stderr and exit
Log and Exitlog.Fatal("error message")Log error and exit with code 1
Conditional Exitif err != nil { os. Exit(1) }Exit only on error
Cleanup Before Exitcleanup(); os.Exit(code)Manual cleanup (defers won't run)
Return from Mainreturn // from main()Preferred - runs deferred functions
Custom Exit Codeconst ErrConfig = 3; os.Exit(ErrConfig)Application-specific error codes

Best Practices

PracticeRecommendationReason
Prefer ReturnReturn from main() instead of os.ExitAllows deferred functions to run
Use Exit in MainOnly call os.Exit from main or initMakes testing easier, clearer control flow
Return ErrorsReturn errors from functions, handle in mainBetter testability and composability
Document Exit CodesDocument what each exit code meansHelps users and scripts understand failures
Use log. Fatal SparinglyPrefer returning errors and exiting in mainMakes code more testable
Stderr for ErrorsPrint errors to os.Stderr, not os.StdoutFollows Unix conventions
Cleanup ResourcesManually cleanup before calling os.ExitDeferred functions won't run

Exit vs Return in Main

Aspectos.Exit()return from main()
Deferred functionsDo not runRun normally
Exit codeCustom codeAlways 0
TestabilityHarder to testEasier to test
Resource cleanupManual onlyAutomatic via defer
Use caseWhen you need non-zero exit codeNormal successful completion

Testing Exit Behavior

TechniqueApproachBenefits
Separate LogicExtract logic to testable functionsTest logic without testing exit
Return Exit CodeHave main() call run() that returns intTest run() function independently
Subprocess TestsUse exec. Command in testsTest actual exit behavior
Mock ExitCreate variable for exit functionReplace os.Exit in tests

Common Exit Scenarios

ScenarioRecommended Exit CodeExample
Successful completion0Normal program completion
Invalid arguments1 or 64Missing or incorrect CLI arguments
Configuration error78Invalid configuration file
File not found66Required file doesn't exist
Permission denied77Insufficient permissions
Network error1Connection failed
Database error1Database connection failed
User interruption130Ctrl+C pressed