{"id":13526419,"url":"https://github.com/uber-go/nilaway","last_synced_at":"2025-05-14T01:02:13.924Z","repository":{"id":184562677,"uuid":"665193375","full_name":"uber-go/nilaway","owner":"uber-go","description":"Static analysis tool to detect potential nil panics in Go code","archived":false,"fork":false,"pushed_at":"2025-03-14T23:22:56.000Z","size":900,"stargazers_count":3332,"open_issues_count":78,"forks_count":72,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-04-03T13:05:39.271Z","etag":null,"topics":["go","nil-pointer","nilability","nilability-analysis","static-analysis"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uber-go.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-11T16:37:19.000Z","updated_at":"2025-04-01T03:35:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"d97353f7-a441-4586-b8dc-3312cc37bf9c","html_url":"https://github.com/uber-go/nilaway","commit_stats":{"total_commits":128,"total_committers":10,"mean_commits":12.8,"dds":0.421875,"last_synced_commit":"ba14292918d814eeaea4de62da2ad0daae92f8b0"},"previous_names":["uber-go/nilaway"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber-go%2Fnilaway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber-go%2Fnilaway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber-go%2Fnilaway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber-go%2Fnilaway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uber-go","download_url":"https://codeload.github.com/uber-go/nilaway/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248261343,"owners_count":21074221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","nil-pointer","nilability","nilability-analysis","static-analysis"],"created_at":"2024-08-01T06:01:29.445Z","updated_at":"2025-05-14T01:02:13.917Z","avatar_url":"https://github.com/uber-go.png","language":"Go","readme":"# NilAway\n\n[![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]\n\n\u003e [!WARNING]  \n\u003e NilAway is currently under active development: false positives and breaking changes can happen. \n\u003e We highly appreciate any feedback and contributions!\n\nNilAway is a static analysis tool that seeks to help developers avoid nil panics in production by catching them at \ncompile time rather than runtime. NilAway is similar to the standard\n[nilness analyzer](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness), however, it employs much more \nsophisticated and powerful static analysis techniques to track nil flows within a package as well _across_ packages, and\nreport errors providing users with the nilness flows for easier debugging.\n\nNilAway enjoys three key properties that make it stand out:\n\n* It is **fully-automated**: NilAway is equipped with an inference engine, making it require _no_ any additional \ninformation from the developers (e.g., annotations) besides standard Go code.\n\n* It is **fast**: we have designed NilAway to be fast and scalable, making it suitable for large codebases. In our\nmeasurements, we have observed less than 5% build-time overhead when NilAway is enabled. We are also constantly applying\noptimizations to further reduce its footprint.\n\n* It is **practical**: it does not prevent _all_ possible nil panics in your code, but it catches most of the potential\nnil panics we have observed in production, allowing NilAway to maintain a good balance between usefulness and build-time \noverhead.\n\n:star2: For more detailed technical discussion, please check our [Wiki][wiki], [Engineering Blog][blog], and paper (WIP).\n\n## Running NilAway\n\nNilAway is implemented using the standard [go/analysis][go-analysis], making it easy to integrate with existing analyzer\ndrivers (i.e., [golangci-lint][golangci-lint], [nogo][nogo], or [running as a standalone checker][singlechecker]).\n\n\u003e [!IMPORTANT]  \n\u003e By default, NilAway analyzes _all_ Go code, including the standard libraries and dependencies. This helps NilAway \n\u003e better understand the code form dependencies and reduce its false negatives. However, this would also incur a \n\u003e significant performance cost (only once for drivers with modular support) and increase the number of non-actionable \n\u003e errors in dependencies, for large Go projects with a lot of dependencies.\n\u003e \n\u003e We highly recommend using the [include-pkgs][include-pkgs-flag] flag to narrow down the analysis to your project's \n\u003e code exclusively. This directs NilAway to skip analyzing dependencies (e.g., third-party libraries), allowing you to \n\u003e focus solely on potential nil panics reported by NilAway in your first-party code!\n\n### Standalone Checker\n\n\u003e [!IMPORTANT]  \n\u003e Due to the sophistication of the analyses that NilAway does, NilAway caches its findings about a \n\u003e particular package via the [Fact Mechanism][fact-mechanism] from the [go/analysis][go-analysis] \n\u003e framework. Therefore, it is _highly_ recommended to leverage a driver that supports modular \n\u003e analysis (i.e., bazel/nogo or golangci-lint, but _not_ the standalone checker since it stores all \n\u003e facts in memory) for better performance on large projects. The standalone checker is provided\n\u003e more for evaluation purposes since it is easy to get started.\n\nInstall the binary from source by running: \n```shell\ngo install go.uber.org/nilaway/cmd/nilaway@latest\n```\n\nThen, run the linter by:\n```shell\nnilaway -include-pkgs=\"\u003cYOUR_PKG_PREFIX\u003e,\u003cYOUR_PKG_PREFIX_2\u003e\" ./...\n```\n\n\u003e [!TIP]  \n\u003e Disable the `pretty-print` flag when output as JSON:\n\u003e ```shell\n\u003e nilaway -json -pretty-print=false -include-pkgs=\"\u003cYOUR_PKG_PREFIX\u003e,\u003cYOUR_PKG_PREFIX_2\u003e\" ./...\n\u003e ```\n\n\n### golangci-lint (\u003e= v1.57.0)\n\nNilAway, in its current form, can report false positives. This unfortunately hinders its immediate \nmerging in [golangci-lint][golangci-lint] and be offered as a linter (see [PR#4045][pr-4045]). \nTherefore, you need to build NilAway as a plugin to golangci-lint to be executed as a private \nlinter. There are two plugin systems in golangci-lint, and it is much easier to use the \n[Module Plugin System][golangci-lint-module-plugin] (introduced since v1.57.0), and it is the only \nsupported approach to run NilAway in golangci-lint.\n\n(1) Create a `.custom-gcl.yml` file at the root of the repository if you have not done so, add the\nfollowing content:\n\n```yaml\n# This has to be \u003e= v1.57.0 for module plugin system support.\nversion: v1.57.0\nplugins:\n  - module: \"go.uber.org/nilaway\"\n    import: \"go.uber.org/nilaway/cmd/gclplugin\"\n    version: latest # Or a fixed version for reproducible builds.\n```\n\n(2) Add NilAway to the linter configuration file `.golangci.yaml`:\n\nFor golangci-lint v2:\n\n```yaml\nversion: \"2\"\nlinters:\n  enable:\n    - nilaway\n  settings:\n    custom:\n      nilaway:\n        type: module\n        description: Static analysis tool to detect potential nil panics in Go code.\n        settings:\n          # Settings must be a \"map from string to string\" to mimic command line flags: the keys are\n          # flag names and the values are the values to the particular flags.\n          include-pkgs: \"\u003cYOUR_PACKAGE_PREFIXES\u003e\"\n```\n\n\n\u003cdetails\u003e\n\n\u003csummary\u003eFor golangci-lint v1:\u003c/summary\u003e\n\n```yaml\nlinters-settings:\n  custom:\n    nilaway:\n      type: \"module\"\n      description: Static analysis tool to detect potential nil panics in Go code.\n      settings:\n        # Settings must be a \"map from string to string\" to mimic command line flags: the keys are\n        # flag names and the values are the values to the particular flags.\n        include-pkgs: \"\u003cYOUR_PACKAGE_PREFIXES\u003e\"\n# NilAway can be referred to as `nilaway` just like any other golangci-lint analyzers in other \n# parts of the configuration file.\n```\n\n\u003c/details\u003e\n\n(3) Build a custom golangci-lint binary with NilAway included:\n\n```shell\n# Note that your `golangci-lint` to bootstrap the custom binary must also be version \u003e= v1.57.0.\n$ golangci-lint custom\n```\n\nBy default, the custom binary will be built at `.` with the name `custom-gcl`, which can be further\ncustomized in `.custom-gcl.yml` file (see [Module Plugin System][golangci-lint-module-plugin] for\ninstructions).\n\n\u003e [!TIP]  \n\u003e Cache the custom binary to avoid having to build it again to save resources, you can use the\n\u003e hash of the `.custom-gcl.yml` file as the cache key if you are using a fixed version of NilAway.\n\u003e If you are using `latest` as NilAway version, you can append the date of build to the cache key \n\u003e to force cache expiration after certain time period.\n\n(4) Run the custom binary instead of `golangci-lint`:\n\n```shell\n# Arguments are the same as `golangci-lint`.\n$ ./custom-gcl run ./...\n```\n\n### Bazel/nogo\n\nRunning with bazel/nogo requires slightly more efforts. First follow the instructions from [rules_go][rules-go], \n[gazelle][gazelle], and [nogo][nogo] to set up your Go project such that it can be built with bazel/nogo with no or \ndefault set of linters configured. Then,\n\n(1) Add `import _ \"go.uber.org/nilaway\"` to your `tools.go` file (or other file that you use for configuring tool \ndependencies, see [How can I track tool dependencies for a module?][track-tool-dependencies] from Go Modules \ndocumentation) to avoid `go mod tidy` from removing NilAway as a tool dependency.\n\n(2) Run the following commands to add NilAway as a tool dependency to your project:\n```bash\n# Get NilAway as a dependency, as well as getting its transitive dependencies in go.mod file.\n$ go get go.uber.org/nilaway@latest\n# This should not remove NilAway as a dependency in your go.mod file.\n$ go mod tidy\n# Run gazelle to sync dependencies from go.mod to WORKSPACE file.\n$ bazel run //:gazelle -- update-repos -from_file=go.mod\n```\n\n(3) Add NilAway to nogo configurations (usually in top-level `BUILD.bazel` file):\n\n```diff\nnogo(\n    name = \"my_nogo\",\n    visibility = [\"//visibility:public\"],  # must have public visibility\n    deps = [\n+++     \"@org_uber_go_nilaway//:go_default_library\",\n    ],\n    config = \"config.json\",\n)\n```\n\n(4) Run bazel build to see NilAway working (any nogo error will stop the bazel build, you can use the `--keep_going` \nflag to request bazel to build as much as possible):\n\n```bash\n$ bazel build --keep_going //...\n```\n\n(5) See [nogo documentation][nogo-configure-analyzers] on how to pass a configuration JSON to the nogo driver, and see \nour [wiki page][nogo-configure-nilaway] on how to pass configurations to NilAway.\n\n## Code Examples\n\nLet's look at a few examples to see how NilAway can help prevent nil panics.\n\n```go\n// Example 1:\nvar p *P\nif someCondition {\n      p = \u0026P{}\n}\nprint(p.f) // nilness reports NO error here, but NilAway does.\n```\n\nIn this example, the local variable `p` is only initialized when `someCondition` is true. At the field access `p.f`, a\npanic may occur if `someCondition` is false. NilAway is able to catch this potential nil flow and reports the following\nerror showing this nilness flow:\n\n```\ngo.uber.org/example.go:12:9: error: Potential nil panic detected. Observed nil flow from source to dereference point:\n    - go.uber.org/example.go:12:9: unassigned variable `p` accessed field `f`\n```\n\nIf we guard this dereference with a nilness check (`if p != nil`), the error goes away.\n\nNilAway is also able to catch nil flows across functions. For example, consider the following code snippet:\n\n```go\n// Example 2:\nfunc foo() *int {\n      return nil\n}\nfunc bar() {\n     print(*foo()) // nilness reports NO error here, but NilAway does.\n}\n```\n\nIn this example, the function `foo` returns a nil pointer, which is directly dereferenced in `bar`, resulting in a panic\nwhenever `bar` is called. NilAway is able to catch this potential nil flow and reports the following error, describing\nthe nilness flow across function boundaries: \n\n```\ngo.uber.org/example.go:23:13: error: Potential nil panic detected. Observed nil flow from source to dereference point:\n    - go.uber.org/example.go:20:14: literal `nil` returned from `foo()` in position 0\n    - go.uber.org/example.go:23:13: result 0 of `foo()` dereferenced\n```\n\nNote that in the above example, `foo` does not necessarily have to reside in the same package as `bar`. NilAway is able\nto track nil flows across packages as well. Moreover, NilAway handles Go-specific language constructs such as receivers,\ninterfaces, type assertions, type switches, and more.\n\n## Configurations\n\nWe expose a set of flags via the standard flag passing mechanism in [go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis).\nPlease check [wiki/Configuration](https://github.com/uber-go/nilaway/wiki/Configuration) to see the available flags and\nhow to pass them using different linter drivers.\n\n## Support \n\nWe follow the same [version support policy](https://go.dev/doc/devel/release#policy) as the [Go](https://golang.org/) \nproject: we support and test the last two major versions of Go.\n\nPlease feel free to [open a GitHub issue](https://github.com/uber-go/nilaway/issues) if you have any questions, bug \nreports, and feature requests.\n\n## Contributions\n\nWe'd love for you to contribute to NilAway! Please note that once you create a pull request, you will be asked to sign \nour [Uber Contributor License Agreement](https://cla-assistant.io/uber-go/nilaway).\n\n## License\n\nThis project is copyright 2023 Uber Technologies, Inc., and licensed under Apache 2.0.\n\n[go-analysis]: https://pkg.go.dev/golang.org/x/tools/go/analysis\n[golangci-lint]: https://github.com/golangci/golangci-lint\n[golangci-lint-module-plugin]: https://golangci-lint.run/plugins/module-plugins/\n[singlechecker]: https://pkg.go.dev/golang.org/x/tools/go/analysis/singlechecker\n[nogo]: https://github.com/bazelbuild/rules_go/blob/master/go/nogo.rst\n[doc-img]: https://pkg.go.dev/badge/go.uber.org/nilaway.svg\n[doc]: https://pkg.go.dev/go.uber.org/nilaway\n[ci-img]: https://github.com/uber-go/nilaway/actions/workflows/ci.yml/badge.svg\n[ci]: https://github.com/uber-go/nilaway/actions/workflows/ci.yml\n[cov-img]: https://codecov.io/gh/uber-go/nilaway/branch/main/graph/badge.svg\n[cov]: https://codecov.io/gh/uber-go/nilaway\n[wiki]: https://github.com/uber-go/nilaway/wiki\n[blog]: https://www.uber.com/blog/nilaway-practical-nil-panic-detection-for-go/\n[fact-mechanism]: https://pkg.go.dev/golang.org/x/tools/go/analysis#hdr-Modular_analysis_with_Facts\n[include-pkgs-flag]: https://github.com/uber-go/nilaway/wiki/Configuration#include-pkgs\n[pr-4045]: https://github.com/golangci/golangci-lint/issues/4045\n[nilaway-as-a-plugin]: https://golangci-lint.run/contributing/new-linters/#how-to-add-a-private-linter-to-golangci-lint\n[rules-go]: https://github.com/bazelbuild/rules_go\n[gazelle]: https://github.com/bazelbuild/bazel-gazelle\n[track-tool-dependencies]: https://go.dev/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module\n[nogo-configure-analyzers]: https://github.com/bazelbuild/rules_go/blob/master/go/nogo.rst#id14\n[nogo-configure-nilaway]: https://github.com/uber-go/nilaway/wiki/Configuration#nogo\n[nogo-instructions]: https://github.com/uber-go/nilaway?tab=readme-ov-file#bazelnogo\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuber-go%2Fnilaway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuber-go%2Fnilaway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuber-go%2Fnilaway/lists"}