Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

linter err113: do not define dynamic errors, use wrapped static errors instead

Tags:

go

I am using err113 as part of golangci-lint.

It is complaining about ...

foo_test.go:55:61: err113: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"repo gave err\")" (goerr113)
        repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, errors.New("repo gave err")),
                                                                  ^

foo_test.go:22:42: err113: do not define dynamic errors, use wrapped static errors instead: "errors.New(\"oops\")" (goerr113)
    repoMock.EXPECT().FindAll().Return(nil, errors.New("oops"))
                                            ^

What is best way to fix this ?

Quoting https://github.com/Djarvur/go-err113

Also, any call of errors.New() and fmt.Errorf() methods are reported except the calls used to initialise package-level variables and the fmt.Errorf() calls wrapping the other errors.

I am trying to get a idiomatic example for this.

like image 361
k1eran Avatar asked Jun 09 '20 20:06

k1eran


3 Answers

Since GO 1.13 you can define a new error type, wrap it and use it. for example, if you want to return an "operation not permitted" + the operation. you need to implement something like

var OperationNotPermit = errors.New("operation not permitted")

func OperationNotFoundError(op string) error {
    return fmt.Errorf("OperationNotPermit %w : %s", OperationNotPermit, op)
}

then in your code, when you want to return the error,

return nil, OperationNotFoundError(Op)

Let's back to question case:

first, define the custom error and the wapper

var repoError = errors.New("repositoryError")

func RepositoryError(msg string) error {
    return fmt.Errorf("%w: %s", repoError,msg)
}

then in your code,

repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, RepositoryError("YOUR CUSTOM ERROR MESSAGE"))
like image 120
Yuseferi Avatar answered Oct 31 '22 14:10

Yuseferi


Declare a package-level variables as suggested:

 var repoGaveErr = errors.New("repo gave err")

 func someFunc() {
    repoMock.EXPECT().Save(gomock.Eq(&foooBarBar)).Return(nil, repoGaveErr)
 }

Every call to errors.New allocates a new unique error value. The application creates a single value representing the error by declaring the package-level variable.

There are two motivations for the single value:

  • The application can compare values for equality to check for a specific error condition.

  • Reduce memory allocations (although probably not a big deal in practice)

The value io.EOF is a canonical example.

like image 17
thwd Avatar answered Oct 31 '22 14:10

thwd


Since it hasn't been said before, you probably don't need to define package level errors for tests. Given the idea is to wrap errors so they can be compared and unwrapped in the caller, returning a dynamic error in a test is fine as long as the purposes of your test are served.

like image 4
Kyle Chadha Avatar answered Oct 31 '22 15:10

Kyle Chadha