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
                    ^
    
Common juju errors and functions to annotate errors. Based on juju/errgo

errors import "github.com/juju/errors" The juju/errors provides an easy way to annotate errors without losing the original error context. The exporte

Dec 30, 2022
Linter for errors.Is and errors.As

erris erris is a program for checking that errors are compared or type asserted using go1.13 errors.Is and errors.As functions. Install go get -u gith

Nov 27, 2022
An errors package optimized for the pkg/errors package
An errors package optimized for the pkg/errors package

errors An errors package optimized for the pkg/errors package Use Download and install go get github.com/dobyte/errors API // New Wrapping for errors.

Mar 2, 2022
🔐 Wrap keys from HSM using CKM_RSA_AES_KEY_WRAP step by step

?? pkcs11-key-wrap Wrap keys from HSM using CKM_RSA_AES_KEY_WRAP step by step. This tool can be used for example for exporting keys from Amazon's Clou

Aug 15, 2022
generic wrap for standard lib of golang.

Generic Std generic wrap for standard lib of golang. Generic will be supported in go 1.18. But for now, standard lib will not support generic containe

Mar 18, 2022
Wrap contains a method for wrapping one Go error with another.

Note: this code is still in alpha stage. It works but it may change subtly in the near future, depending on what comes out of golang/go#52607. Wrap.Wi

Jun 27, 2022
eris provides a better way to handle, trace, and log errors in Go 🎆

eris Package eris provides a better way to handle, trace, and log errors in Go. go get github.com/rotisserie/eris Why you'll want to switch to eris Us

Dec 29, 2022
Golang errors with stack trace and source fragments.
Golang errors with stack trace and source fragments.

Golang Errors with Stack Trace and Source Fragments Tired of uninformative error output? Probably this will be more convenient: Example package main

Dec 17, 2022
Golang errors with stacktrace and context

merry Add context to errors, including automatic stack capture, cause chains, HTTP status code, user messages, and arbitrary values. The package is la

Nov 19, 2022
This structured Error package wraps errors with context and other info

RErr package This structured Error package wraps errors with context and other info. It can be used to enrich logging, for example with a structured l

Jan 21, 2022
The Emperor takes care of all errors personally
The Emperor takes care of all errors personally

The Emperor takes care of all errors personally. Go's philosophy encourages to gracefully handle errors whenever possible, but some times recovering f

Jan 9, 2023
A drop-in replacement for Go errors, with some added sugar! Unwrap user-friendly messages, HTTP status code, easy wrapping with multiple error types.
A drop-in replacement for Go errors, with some added sugar! Unwrap user-friendly messages, HTTP status code, easy wrapping with multiple error types.

Errors Errors package is a drop-in replacement of the built-in Go errors package with no external dependencies. It lets you create errors of 11 differ

Dec 6, 2022
A Go (golang) package for representing a list of errors as a single error.

go-multierror go-multierror is a package for Go that provides a mechanism for representing a list of error values as a single error. This allows a fun

Jan 1, 2023
Hierarchical errors reporting done right in Golang

Hierarchical errors made right Hate seeing error: exit status 128 in the output of programs without actual explanation what is going wrong? Or, maybe,

Nov 9, 2021
harvest Go errors with ease

Pears Harvest Go Errors with Ease Introduction Pears helps reduce the boilerplate and ensure correctness for common error-handling scenarios: Panic re

Apr 25, 2021
SupErr -- Go stdlib errors with super powers

superr SupErr -- Go stdlib errors with super powers. Pronounced super with a French accent :D Build a stack of errors compatible with Go stdlib and er

Nov 15, 2022
Package semerr helps to work with errors in Golang.
Package semerr helps to work with errors in Golang.

semerr Package semerr helps to work with errors in Golang. Const error An error that can be defined as const. var errMutable error = errors.New("mutab

Oct 30, 2022
A Nostress Errors Package For Golang

A Nostress Errors Package For Golang

Nov 2, 2021
Simple Go library for typed errors creation

go-typed-errors Why this repo was created? Main reason was to create additional methods for better error typing support. Why not to use errors.As and

Nov 5, 2021