nilguard is a Go static analyzer that enforces a defensive coding policy:
any pointer used in a function must be nil-checked somewhere in that function.
go vet and Staticcheck catch definite or inconsistent nil dereferences. They do not
enforce the absence of a nil guard as a policy. nilguard fills that gap.
go install github.com/HMetcalfe/nilguard/cmd/nilguard@latestbrew tap hmetcalfew/tap
brew install nilguardgit clone https://github.com/HMetcalfe/nilguard
cd nilguard
make buildnilguard ./...go install github.com/HMetcalfe/nilguard/cmd/nilguard-vet@latest
go vet -vettool=$(which nilguard-vet) ./...Build the plugin and reference it in .golangci.yml:
make plugin # builds bin/nilguard.so (Linux only)linters:
enable:
- nilguard
linters-settings:
custom:
nilguard:
path: ./bin/nilguard.so
description: "Flags pointer uses without a nil check"
original-url: "https://github.com/HMetcalfe/nilguard"nilguard flags pointer uses that lack a nil-check anywhere in the same function:
| Use Pattern | Example |
|---|---|
| Star dereference | *p |
| Selector on pointer | p.Field |
| Method call on pointer | p.Method() |
if p != nil { ... }if p == nil { return }(orpanic,break,continue,goto)- Compound conditions:
if p != nil && q != nil { ... } - Guard-then-exit:
if p == nil || q == nil { return } - Two-value type assertion:
v, ok := x.(*T)(marksvas checked) - Type switch:
switch v := x.(type) { case *T: }(marksvas checked per case)
A single qualifying check anywhere in the function satisfies all uses of that pointer.
Add //nolint:nilguard to suppress a specific line:
_ = p.X //nolint:nilguard- No alias tracking —
q := p; q.Method()is not traced back top - No cross-function analysis — constructors and factory functions are not treated specially
- No flow-sensitive dominance — a nil-check anywhere in the function satisfies all uses
- Nested function literals — analyzed independently; a check in the outer function does not satisfy uses in a closure
- No
errors.Astracking —errors.As(err, &target)is not recognized as a nil guard fortarget - golangci-lint plugin — requires
-buildmode=plugin, which only works on Linux
Requires Go 1.25+.
make test # run tests
make lint # golangci-lint + staticcheck
make build # build CLI + vettool
make plugin # build golangci-lint plugin (Linux only)
make clean # remove bin/Pushing a version tag triggers the GitHub Actions release pipeline:
git tag v0.1.0
git push origin v0.1.0Apache 2.0. See LICENSE for details.