# errcheck: finding the errors your Go code throws away

> A small standalone linter that reports error returns nobody looked at, with an exclusion file for the cases where you meant to ignore them.

**kisielk/errcheck** — errcheck checks that you checked errors.

- Repository: https://github.com/kisielk/errcheck
- Stars: 2,530 · Forks: 151
- Language: Go
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/kisielk-errcheck

## A discarded error is legal Go

Go's compiler will not stop you from calling a function that returns an error and then ignoring the result entirely. That makes sense for the small number of functions whose errors are documented never to fire, and it makes a mistake everywhere else. errcheck exists to close that gap in one line of intent: for all callables that are not in the excluded list, all returned errors must be either assigned to a variable or explicitly discarded by being assigned to `_`.

The project states its limitation up front, which is the most useful sentence on the page. errcheck does not do any further analysis on assigned errors. So this passes without a complaint:

```go
err := foo()

// First error is discarded
err = bar()
if err != nil {
       ...
}
```

The first return value is overwritten before anything checks it, and errcheck says nothing. For analysis at that level it points at staticcheck. That division of labour is the honest framing of what this tool is: a call site reporter, not a data flow analyser.

## Installing and choosing what to check

Installation is a single `go install`, and the README states the floor plainly: errcheck requires Go 1.25 or newer.

```bash
go install github.com/kisielk/errcheck@latest
```

The invocation is a package path. Give it the one package you care about:

```bash
errcheck github.com/kisielk/errcheck/testdata
```

Or check everything beneath the current directory, which is the form you want in CI:

```bash
errcheck ./...
```

There is a third form, `errcheck all`, which covers all packages in `$GOPATH` and `$GOROOT`. That is a debugging move rather than a CI one, since it will surface errors in code you do not own.

Exit codes are simple enough to script against. errcheck returns 1 if any problems were found in the checked files, and 2 if there were any other failures. That split matters for automation, because a 2 means the run itself broke, not that the code is dirty.

The module definition is minimal and explains the build story. `go.mod` declares Go 1.25.0 and requires `golang.org/x/tools` v0.44.0, with `golang.org/x/mod` and `golang.org/x/sync` as indirect dependencies. The code lives in `errcheck/`, with `main.go` at the root and `main_test.go` beside it, plus a `testdata/` directory.

## Flags for assertions, blanks and build tags

Most behaviour is reached through flags. `-tags` takes a space-separated list of build tags, just like `go build`, and you need it if your codebase uses custom tags or errcheck will analyse the wrong set of files. `-asserts` enables checking for ignored type assertion results and takes no arguments. `-blank` enables checking for assignments of errors to the blank identifier, also with no arguments, and it is off by default, which means a function called only for its side effects with `_ = foo()` will pass unless you ask otherwise.

`-abspath` prints absolute paths to files with unchecked errors, which is what you want when a CI log has to link back to a line. `-mod` sets the module download mode to either `readonly` or `vendor`.

There is also a `go/analysis` entry point. The package provides an `Analyzer` instance usable through the `go/analysis` API, currently supporting the flags `blank`, `assert`, `exclude` and `excludeonly`. The README labels that API experimental and warns it may change, so if you are embedding errcheck in golangci-lint or another driver, pin your expectations loosely.

## The exclude file and its exact signature format

The `-exclude` flag takes a path to a file listing one function signature per line:

```bash
errcheck -exclude errcheck_excludes.txt path/to/package
```

The format is specific enough to be worth reading twice. A plain function is `package.FunctionName`. A method on a value receiver is `(package.Receiver).MethodName`, and on a pointer receiver it is `(*package.Receiver).MethodName`. If the function name is followed by a string of the form `(TYPE)`, the call is excluded only when the type of the first argument is `TYPE`. There are two special suffixes, `(os.Stdout)` and `(os.Stderr)`, which exclude the function only when the first argument is literally one of those. An example file:

```
io.Copy(*bytes.Buffer)
io.Copy(os.Stdout)
os.ReadFile

// Sometimes we don't care if a HTTP request fails.
(*net/http.Client).Do
```

Empty lines and lines starting with `//` are ignored. By default this file is combined with an internal list of standard library functions that have an error return type but are documented never to return an error, and `-excludeonly` disables that built-in list so your file is the whole story. `-verbose` prints the resulting list of added excludes, which is the fastest way to find out why a function you expected to be flagged is not.

Vendored dependencies need their full import path rather than the short package name, so excluding a vendored `fmt2.Println` means writing something like `example.com/yourpkg/vendor/example.net/fmt2.Println`.

## The deprecated flag set and what replaced it

The README keeps a section for the older approach because the flags still work. `-ignore` takes a comma-separated list of `package:regex` pairs, where the package may be omitted so the regex applies everywhere:

```bash
errcheck -ignore '[rR]ead|[wW]rite' path/to/package
```

```bash
errcheck -ignore 'fmt:[FS]?[Pp]rint*' path/to/package
```

`-ignorepkg` takes bare package import paths, so `errcheck -ignorepkg 'fmt,encoding/binary' path/to/package` is equivalent to `-ignore 'fmt:.*,encoding/binary:.*'`. When a package appears in both, `-ignorepkg` wins and everything in that package is skipped. There is a detail that surprises people: by default the whole `fmt` package is ignored unless you give it a regex, and to turn that off you have to supply a regex that matches nothing, such as `errcheck -ignore 'fmt:a^' path/to/package`.

`-ignoretests` disables checking of `_test.go` files and `-ignoregenerated` disables checking of generated source code. Neither takes arguments.

For editor feedback there are two integrations. go-errcheck.el gives Emacs a `go-errcheck` command with customizable variables for passing flags, and vim-go can run errcheck through both `:GoErrCheck` and `:GoMetaLinter`.

## Release notes that quietly change your results

The three most recent releases each alter what errcheck reports without touching its command line surface. v1.10.0, published 2026-02-26, excluded crypto/rand.Read by default and added a README change clarifying the purpose and limitations of the program. v1.20.0, published 2026-05-12, excluded crypto/sha3.Read and crypto/sha3.Write by default, added support for excludes for functions with type parameters, bumped GitHub Actions, and raised the minimum Go version to 1.25. That default list is a moving target: if a package passed clean last month and fails now, or the reverse, the standard library exclusion list is the first thing to inspect with `-verbose`.

Version 1.9.0, from 2025-02-19, added Go 1.24 support, dropped Go 1.18 through 1.21 because of `golang.org/x/tools`, removed the no longer relevant `fmtTags`, and deprecated `ErrNoGoFiles` as something never returned. The v1.20.0 changelog link compares against v1.10.0 directly, so the numbered releases skip from 1.10 to 1.20 in what the project publishes, which is worth knowing if you are trying to work out when a behaviour changed.

This repository is not archived and the last push was on 2026-05-12, the same day as v1.20.0, so the line is still moving. At 2,531 stars and 17 open issues it remains the tool people reach for when they want the call sites and nothing else.

## Conclusion

errcheck is worth adding to a Go project for one narrow reason that no compiler gives you: a discarded error return is legal Go, and no amount of vetting catches it by eye. The tool is deliberately shallow, reporting the call and leaving the judgement to you, and it points at staticcheck for the analysis it does not perform. The one operational detail to get right is the exclude file, because the built-in list has quietly grown between releases, with crypto/rand.Read added in v1.10.0 and the crypto/sha3 pair added in v1.20.0, so a clean result before an upgrade may not be clean after. Install it, point it at one package path, and read what it prints before you wire it into CI.

## FAQ

### What does errcheck actually detect in Go code?

For all callables that are not in the excluded list, all returned errors must be either assigned to a variable or explicitly discarded by being assigned to `_`. It reports the call site and stops there. It does not do any further analysis on assigned errors, so an error that is assigned and then overwritten without being checked passes, and staticcheck is the tool the README points at for that case.

### How do I stop errcheck reporting functions I deliberately ignore?

Use the `-exclude` flag with a file containing one signature per line, such as `errcheck -exclude errcheck_excludes.txt path/to/package`. Functions are written as `package.FunctionName`, methods as `(package.Receiver).MethodName` or `(*package.Receiver).MethodName`, and a `(TYPE)` suffix narrows the exclusion to calls whose first argument has that type. This list is merged with a built-in list of standard library functions documented never to return an error, which `-excludeonly` disables.

### Does errcheck work with golangci-lint and other go/analysis drivers?

The package provides an `Analyzer` instance for the `go/analysis` API, currently supporting the flags `blank`, `assert`, `exclude` and `excludeonly`. The README labels that API experimental and notes it may change in the future, so it is usable for embedding but worth pinning loosely.

### Why is errcheck not reporting my `_ = foo()` calls?

Assignments to the blank identifier are only checked when you pass the `-blank` flag, which takes no arguments and is off by default. The same is true of ignored type assertion results, which need `-asserts`. If a build-tagged file is not being checked at all, `-tags` takes a space-separated list of tags the same way `go build` does.

### What Go version does errcheck need?

The README states that errcheck requires Go 1.25 or newer, and the module declaration in `go.mod` matches at Go 1.25.0. Support for Go 1.18 through 1.21 was dropped in v1.9.0, and the minimum was raised to 1.25 in v1.20.0.

## Sources

- [Issues](https://github.com/kisielk/errcheck/issues)
- [kisielk/errcheck on GitHub](https://github.com/kisielk/errcheck)
- [License: MIT](https://github.com/kisielk/errcheck/blob/master/LICENSE)
- [README](https://github.com/kisielk/errcheck/blob/master/README.md)
- [Releases](https://github.com/kisielk/errcheck/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kisielk-errcheck
