Go tool to wrap and fix errors with the new %w verb directive

errwrap

Wrap and fix Go errors with the new %w verb directive. This tool analyzes fmt.Errorf() calls and reports calls that contain a verb directive that is different than the new %w verb directive introduced in Go v1.13. It's also capable of rewriting calls to use the new %w wrap verb directive.

errwrap

Install

# minimum v1.16 is required
go install github.com/fatih/errwrap@latest

or download one of the pre-compiled binaries from the releases page and copy to the desired location.

Usage

By default, errwrap prints the output of the analyzer to stdout. You can pass a file, directory or a Go package:

$ errwrap foo.go # pass a file
$ errwrap ./...  # recursively analyze all files
$ errwrap github.com/fatih/gomodifytags # or pass a package

When called it displays the error with the line and column:

[email protected]/main.go:200:16: call could wrap the error with error-wrapping directive %w
[email protected]/main.go:641:17: call could wrap the error with error-wrapping directive %w
[email protected]/main.go:749:15: call could wrap the error with error-wrapping directive %w

errwrap is also able to rewrite your source code to replace any verb directive used for an error type with the %w verb directive. Assume we have the following source code:

$ cat demo.go
package main

import (
        "errors"
        "fmt"
)

func main() {
        _ = foo()
}

func foo() error {
        err := errors.New("bar!")
        return fmt.Errorf("foo failed: %s: %w bar ...", "foo", err)
}

Calling errwrap with the -fix flag will rewrite the source code:

$ errwrap -fix main.go
main.go:14:9: call could wrap the error with error-wrapping directive %w
diff --git a/main.go b/main.go
index 41d1c42..6cb42b8 100644
--- a/main.go
+++ b/main.go
@@ -11,5 +11,5 @@ func main() {

 func foo() error {
        err := errors.New("bar!")
-       return fmt.Errorf("failed for %s with error: %s", "foo", err)
+       return fmt.Errorf("failed for %s with error: %w", "foo", err)
 }

Whether to Wrap or not?

Wrapping an error is not always the best approach. Wrapping exposes the underlying error and makes it part of your public API. This means clients who rely on them could see breaking changes if you change your underlying implementation or don't wrap anymore.

The blog post Working with Errors in Go 1.13 contains a section called Whether to Wrap that explains this in more detail

Credits

This tool is built on top of the excellent go/analysis package that makes it easy to write custom analyzers in Go. If you're interested in writing a tool, check out my Using go/analysis to write a custom linter blog post.

Also part of the code that parses the verb directives is from the go/analysis/passes/printf analyzer. It's a simplified version and might contain discrepancies.

Owner
Fatih Arslan
Software Engineer. Gopher and Coffee geek. Creator of vim-go. Tool maker.
Fatih Arslan
Comments
  • feat: detect and fix err.String() calls

    feat: detect and fix err.String() calls

    Adds support for detecting and fixing the following Errorf case where the developer had previously add a call to .Error() in their Errorf statement:

    -fmt.Errorf("failed for %s with error: %s", "foo", err.Error())
    +fmt.Errorf("failed for %s with error: %w", "foo", err)
    

    This PR also switches to running the tests with the new analysistest.RunWithSuggestedFixes helper to verify the -fix behaviour using golden files.

  • Leading whitespace corrupted

    Leading whitespace corrupted

    
            if err := os.Rename(sourceFilename, destinationFilename); err
     != nil {
    -               err = fmt.Errorf("Could not move file: %v to %v: %v",
    -                       sourceFilename, destinationFilename, err)
    +               err = fmt.Errorf("Could not move file: %v to %v: %w",
    +       sourceFilename, destinationFilename, err)
                    log.Add("err", err)
    
    
  • errwrap -fix needs multiple invocations if there are a number of wrappings to perform in a file

    errwrap -fix needs multiple invocations if there are a number of wrappings to perform in a file

    Is there an intentional limit on the number of fixes to apply in a single invocation? I noticed that if I use errwrap to attempt to migrate a legacy project to using 1.13 style error wrapping, it takes a few invocations to make it fix everything:

    % errwrap -fix .
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:86:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:89:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:92:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:95:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:98:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:101:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:126:10: call could wrap the error with error-wrapping directive %w
    
    % errwrap -fix .
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:98:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:95:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:101:10: call could wrap the error with error-wrapping directive %w
    /Users/example/.local/src/github.ibm.com/org/repo/pkg/action/metrics/screenshot.go:126:10: call could wrap the error with error-wrapping directive %w
    
    % errwrap -fix .
    
    %
    
    
  • Fix bug to allow detecting multiple wrap directives

    Fix bug to allow detecting multiple wrap directives

    Thanks for this project @fatih, I was writing test cases in an effort to understanding the project and I was unable to replicate the scenario for multiple %w directives. This bug fix allows for it.

    Happy to hear your thoughts on this

  • update go.mod and go.sum

    update go.mod and go.sum

    When I tried errwrap I was getting this error:

    https://github.com/golang/go/issues/37617

    Updating tools fixes the problem for me.

    Also set go.mod's go version to 1.17.

  • Don't clobber the AST when generating suggested fixes

    Don't clobber the AST when generating suggested fixes

    analysis/unitchecker calls multiple analyzers in parallel, using the same AST. This creates a race where clobbering the AST might result in unexpected behaviour from other linters. In particular, linters that use the buildssa analyzer can panic with an error about a non-constant BasicLit, because it builds up a set of constants and then expects that set to be the same later in its analysis process.

    Instead make a new CallExpr, and use that for the rewriting step.

  • What difference from go-errorlint?

    What difference from go-errorlint?

    Hello!

    go-errorlint is more popular linter, because it's a part of golangci-lint.

    And it has functionality to detect %w: https://github.com/polyfloyd/go-errorlint#fmterrorf-wrapping-verb

    :(

  • How about enabling workflows for PRs?

    How about enabling workflows for PRs?

    I am new to workflows but I think it might be nice to enable it for PRs, too?

    Or is it supposed to run on forks? If so, it's a bit inconvenient to see if PRs follow the expected standards.

  • fix minor issues reported by linter

    fix minor issues reported by linter

    Fix the following issues:

    errwrap/errwrap.go:208:2: `pos` is unused (structcheck)
            pos      int    // index of the verb in the format string
            ^
    errwrap/errwrap.go:180:3: S1023: redundant `return` statement (gosimple)
                    return
                    ^
    
go HTTP client that makes it plain simple to configure TLS, basic auth, retries on specific errors, keep-alive connections, logging, timeouts etc.

goat Goat, is an HTTP client built on top of a standard Go http package, that is extremely easy to configure; no googling required. The idea is simila

Jun 25, 2022
Traefik proxy plugin to extract HTTP header value and create a new header with extracted value

Copy header value Traefik plugin Traefik plugin that copies HTTP header value with format key1=value1; key2=value2 into a new header. Motivation for t

May 26, 2022
A new way of working with Protocol Buffers.

Buf All documentation is hosted at https://buf.build. Please head over there for more details. Goal Buf’s long-term goal is to enable schema-driven de

Jan 1, 2023
the pluto is a gateway new time, high performance, high stable, high availability, easy to use

pluto the pluto is a gateway new time, high performance, high stable, high availability, easy to use Acknowledgments thanks nbio for providing low lev

Sep 19, 2021
A new Minecraft: Pi Edition Launcher

Pipan About [TODO] Building Pipan is a go project. go build and then run the resultant executable. You will need go >= 1.16 for module support, and a

Oct 11, 2022
Notifies you about new matrix messages on your LaMetric Time

Matrix -> LaMetric Time bridge This small golang app notifies you about new messages on your LaMetric Time. This should be run on a Raspberry Pi or so

Sep 29, 2022
Server-tool - A simple tool to run and create Minecraft servers

Server Tool A simple tool to run and maintain different Minecraft servers. This

Dec 15, 2022
This is a tool that allows you to check minecraft names availability, this tool can do around 3000~ names a minute or more!

Checker This is a tool that allows you to check minecraft names availability, this tool can do around 3000~ names a minute or more! Tutorial To instal

Feb 13, 2022
Traefik config validator: a CLI tool to (syntactically) validate your Traefik configuration filesTraefik config validator: a CLI tool to (syntactically) validate your Traefik configuration files
Traefik config validator: a CLI tool to (syntactically) validate your Traefik configuration filesTraefik config validator: a CLI tool to (syntactically) validate your Traefik configuration files

Traefik Config Validator Note This is currently pre-release software. traefik-config-validator is a CLI tool to (syntactically) validate your Traefik

Dec 16, 2021
A tool that makes http requests and outputs the url and the content (optionally to file)

BKK Basic Crawler A tool that makes http requests and outputs the url and the content (optionally to file) How to run.. the tests go test the compiler

Nov 8, 2021
A quick and dirty but useful tool to download each text/html page from the wayback machine for a specific domain and search for keywords within the saved content

wayback-keyword-search A quick and dirty but useful tool to download each text/html page from the wayback machine for a specific domain and search for

Dec 2, 2022
PinGo is a standalone and feature-rich tool for common IP-based reachability checking tasks. Ping or Trace and Observe in real-time the statistics.

pingo As a network champion from designing and implementing to troubleshooting large scale networks - I know that is usually not easy for administrato

Sep 26, 2022
Golang tool to parse netblocks and domain names from SPF and get information about ASN
Golang tool to parse netblocks and domain names from SPF and get information about ASN

gospf Example Install go get github.com/incogbyte/gospf # get from releases ht

Nov 14, 2022
A C/S Tool to Download Torrent Remotely and Retrieve Files Back Over HTTP at Full Speed without ISP Torrent Limitation.

remote-torrent Download Torrent Remotely and Retrieve Files Over HTTP at Full Speed without ISP Torrent Limitation. This repository is an extension to

Sep 30, 2022
Command-line tool and library for Windows remote command execution in Go

WinRM for Go Note: if you're looking for the winrm command-line tool, this has been splitted from this project and is available at winrm-cli This is a

Nov 29, 2022
A tool for IDN homograph attacks and detection.

Ditto is a small tool that accepts a domain name as input and generates all its variants for an homograph attack as output, checking which ones are av

Dec 26, 2022