Skip to content
Ownership and lifecycle

resourcelifetime

Checks owned files, SQL handles, HTTP responses, timers, and compressors are released on every path.

Fix offeredNo

What it detects

Release owned resources on every path. Storing a resource in a partially constructed object does not transfer ownership when an error path returns without that object.

The built-in contracts cover files, transactions, SQL rows and statements, HTTP response bodies, timers and tickers, and gzip/zlib readers and writers.

Checks

Check What it detects
missing-release
Reports owned resources that are not released on every return path.

Why this is flagged

Owned resources are limited and often hold work open elsewhere. Missing cleanup on even one return path can leak file descriptors, database connections, network bodies, timers, or transactions until the program slows down or fails.

Further reading: Effective Go: Defer, Package net/http.

How to fix it

As soon as a resource is acquired successfully, arrange for its matching cleanup on every later return path. Use defer when the current function owns the resource, or transfer it only when the receiver clearly takes ownership.

Examples

Flagged code

Leaked file

func read(path string) error {
// gohawk: owned resource from os.Open is not released on every return path
file, err := os.Open(path)
if err != nil {
return err
}
_ = file
return nil
}

Leaked database rows

func query(ctx context.Context, database *sql.DB) error {
// gohawk: owned resource from sql.QueryContext is not released on every return path
rows, err := database.QueryContext(ctx, "SELECT 1")
if err != nil {
return err
}
_ = rows
return nil
}

Accepted code

func readSafely(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
return nil
}

Options

Knob Default Effect
contracts os,http,sql,time,compress Comma-separated resource contract families: os,http,sql,time,compress.
require-reader-close true Require gzip and zlib readers to be closed.