2

Consider the following test:

import (
    "errors"
    "fmt"
    "testing"
)

func TestError(t *testing.T) {
    err := &MyError{}
    var target error
    fmt.Println(errors.As(err, &target))
}

type MyError struct{}

func (err *MyError) Error() string {
    return "oops!"
}

Running this test returns the build error second argument to errors.As should not be *error.

Go Playground

However, when running the exact same code in main, then the program runs without issues:

package main

import (
    "errors"
    "fmt"
)

func main() {
    err := &MyError{}
    var target error
    fmt.Println(errors.As(err, &target))
}

type MyError struct{}

func (err *MyError) Error() string {
    return "oops!"
}

Go Playground

I am seeing this behavior in the Go Playground and my local development environment, both of which are using Go 1.20.

Is this a bug in Go?

Edit

I can work around the build failure in the test by creating an Error type:

package main

import (
    "errors"
    "fmt"
    "testing"
)

type Error error // <===== Add error type

func TestError(t *testing.T) {
    err := &MyError{}
    var target Error // <===== Use Error type
    fmt.Println(errors.As(err, &target))
}

type MyError struct{}

func (err *MyError) Error() string {
    return "oops!"
}
Sam Herrmann
  • 6,293
  • 4
  • 31
  • 50

1 Answers1

6

The error is reported by the go vet command. The go test command automatically runs go vet to report significant problems. The go build command does not run the go vet command.

The warning is not a bug in Go.

There's no purpose in calling errors.As with a *error as the second argument because you already know that the first argument satisfies the error interface. You are almost certainly doing something wrong.

  • Ah, I overlooked that `go test` runs `go vet`, so that must be the answer why I am only seeing this with `go test`. Having said that, the reason why I came across this is because I was looking into how to use `errors.As` in table-driven tests. There is a representative example of what I am trying to do in the [standard library](https://github.com/golang/go/blob/master/src/errors/wrap_test.go#L204). Note though that they typed `tc.target` as `any`, and to me it seemed that there shouldn't be a reason why `tc.target` can't be typed as `error` and assign different error types in each test case. – Sam Herrmann Feb 17 '23 at 23:04
  • 1
    Your test uses `error` as the type of the target value. The table in the standard library test stores a pointer to a value of the error type. The standard library uses `any` instead of `error` because a pointer to an error does not satisfy the `error` interface. Follow the pattern in the standard library test. Specifically, store a pointer to the target value in the table and pass that value directly to errors.As (do not take address of value in table). – pEnnystEvEns Feb 18 '23 at 02:30