Skip to content
Ownership and lifecycle

exitpolicy

Checks process termination that bypasses registered defers.

Fix offeredNo

What it detects

os.Exit and log.Fatal terminate the process without running deferred calls. Return an error through the normal call stack when cleanup has already been registered on the current path.

Checks

Check What it detects
skipped-defer
Reports immediate process termination that bypasses an earlier defer.

Why this is flagged

Immediate process termination skips deferred cleanup. Buffered output may be lost, temporary files may remain, and resources may not be closed cleanly.

Further reading: os.Exit, log.Fatal.

How to fix it

Return an error through the normal call stack so deferred cleanup can run. If the process must exit, do it once at the top level, after the function that owns the cleanup has returned.

Examples

Flagged code

func run() {
file, _ := os.CreateTemp("", "state")
defer file.Close()
// gohawk: log.Fatal exits without running an earlier defer
log.Fatal("startup failed")
}

Accepted code

func runSafely() error {
file, err := os.CreateTemp("", "state")
if err != nil {
return err
}
defer file.Close()
return nil
}