Overview
Hi @fatih,
Thank you for providing this linter. It has already helped catch several cases where I did not use the %w error-wrapping directive in my projects.
It did however flag one case that may be a false-positive.
I have a project that is still using Go 1.19 and the linter identifies what it believes to be a missing use of %w, but I already have one such usage in place. I understand that this syntax would be valid in Go 1.20, but since the project README indicates that the linter supports Go 1.16 and newer I'm reporting this as a potential problem.
Short version (before following linter advice):
annotatedErrors := make([]error, 0, len(errs))
// ...
annotatedErrors = append(annotatedErrors, fmt.Errorf(
"%w: %v; %s",
err,
errRuntimeTimeoutReached,
runtimeTimeoutReachedAdvice,
))
Linter output:
$ errwrap main.go
main.go:41:48: call could wrap the error with error-wrapping directive %w
Reproducible example
Code after following linter advice:
code example
// main.go
package main
import (
"context"
"errors"
"fmt"
)
// errRuntimeTimeoutReached indicates that plugin runtime exceeded specified
// timeout value.
var errRuntimeTimeoutReached = errors.New("plugin runtime exceeded specified timeout value")
// runtimeTimeoutReachedAdvice offers advice to the sysadmin for routine
// occurrence.
const runtimeTimeoutReachedAdvice string = "consider increasing value if this is routinely encountered"
func annotateError(errs ...error) []error {
isNilErrCollection := func(collection []error) bool {
if len(collection) != 0 {
for _, err := range errs {
if err != nil {
return false
}
}
}
return true
}
switch {
// Process errors as long as the collection is not empty or not composed
// entirely of nil values.
case !isNilErrCollection(errs):
annotatedErrors := make([]error, 0, len(errs))
for _, err := range errs {
if err != nil {
switch {
case errors.Is(err, context.DeadlineExceeded):
annotatedErrors = append(annotatedErrors, fmt.Errorf(
"%w: %w; %s",
err,
errRuntimeTimeoutReached,
runtimeTimeoutReachedAdvice,
))
default:
// Record error unmodified if additional decoration isn't defined
// for the error type.
annotatedErrors = append(annotatedErrors, err)
}
}
}
return annotatedErrors
// No errors were provided for evaluation.
default:
return nil
}
}
func main() {
sampleErr := fmt.Errorf(
"my sample error: %w",
context.DeadlineExceeded,
)
errCollection := annotateError(sampleErr)
fmt.Println(errCollection)
}
// main_test.go
package main
import (
"context"
"fmt"
"testing"
)
func TestAnnotateError(t *testing.T) {
sampleErr := fmt.Errorf(
"my sample error: %w",
context.DeadlineExceeded,
)
errCollection := annotateError(sampleErr)
t.Log(errCollection)
}
Results
If I follow the linter's advice, this is what I get when running the code:
$ go run main.go
[my sample error: context deadline exceeded: %!w(*errors.errorString=&{plugin runtime exceeded specified timeout value}); consider increasing value if this is routinely encountered]
$ go test ./...
# errwrap-false-positive
.\main.go:41:48: fmt.Errorf call has more than one error-wrapping directive %w
FAIL errwrap-false-positive [build failed]
FAIL
Linter version details
$ go version -m $(which errwrap.exe)
C:/Users/atc0005/go/bin/errwrap.exe: go1.19.7
path github.com/fatih/errwrap
mod github.com/fatih/errwrap v1.5.0 h1:/z6jzrekbYYeJukzq9h3nY+SHREDevEB0vJYC4kE9D0=
dep golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
dep golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
dep golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1
Overview
Hi @fatih,
Thank you for providing this linter. It has already helped catch several cases where I did not use the
%werror-wrapping directive in my projects.It did however flag one case that may be a false-positive.
I have a project that is still using Go 1.19 and the linter identifies what it believes to be a missing use of
%w, but I already have one such usage in place. I understand that this syntax would be valid in Go 1.20, but since the project README indicates that the linter supports Go 1.16 and newer I'm reporting this as a potential problem.Short version (before following linter advice):
Linter output:
Reproducible example
Code after following linter advice:
code example
Results
If I follow the linter's advice, this is what I get when running the code:
Linter version details