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

Overview

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/[email protected]

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.

Issues
  • 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.

    opened by dnwe 3
  • 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)
    
    
    opened by tmm1 3
  • 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 .
    
    %
    
    
    opened by dnwe 2
  • 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

    opened by tariq1890 2
  • 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.

    opened by reillywatson 1
  • 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

    :(

    opened by Antonboom 1
  • 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.

    opened by ferhatelmas 1
  • 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
                    ^
    
    opened by tariq1890 0
Releases(v1.4.0)
Owner
Fatih Arslan
Software Engineer. Gopher and Coffee geek. Creator of vim-go. Tool maker.
Fatih Arslan
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

Juju 1.3k May 12, 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

Roman Budnikov 51 Mar 3, 2022
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.

Fuxiao 3 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

Smallstep 6 Mar 21, 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

Tobias Yin 1 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

Nate Finch 3 May 3, 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

null 1k May 15, 2022
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

null 710 May 13, 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

Russ Egan 248 Apr 5, 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

Rohan Allison 0 Jan 21, 2022
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

Emperror 248 Apr 17, 2022
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

Kamaleshwar 41 May 10, 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

HashiCorp 1.6k May 18, 2022
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,

reconquest 74 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

Billy Peake 7 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

Golang libraries for everyone 22 Mar 2, 2022
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

Maxim Krivchun 3 Mar 27, 2022
A Nostress Errors Package For Golang

A Nostress Errors Package For Golang

null 0 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

Bogdan 2 Nov 5, 2021