Skip to content

assertions: correct the type assertion of ErrorAs#183

Merged
shoenig merged 1 commit intomainfrom
better-error-as
Apr 17, 2026
Merged

assertions: correct the type assertion of ErrorAs#183
shoenig merged 1 commit intomainfrom
better-error-as

Conversation

@shoenig
Copy link
Copy Markdown
Owner

@shoenig shoenig commented Apr 16, 2026

After bumping the go directive version in go.mod to 1.21 the vet tool
is complaining about the ErrorAs assertion.

➜ go vet ./...
internal/assertions/assertions.go:208:6: second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type

The linter warning is a bit of a red-herring - in fact the Target
parameter for our ErrorAs assertion has been incorrect this whole time.
It should be any. Currently it is restricting types to be a concrete
type that implements the error interface, which is not a requirement of
errors.As.

In fact you can use errors.As to assert your err satisfies any interface
you choose - but the examples in the Go docs do not make this clear (imo).

For example you could have some error type:

type NetworkError interface {
    Error() error
    Timeout() bool
}

And you want to check if your error implements Timeout(), which you
can do using errors.As, e.g.

type IO interface {
    Timeout() bool
}

var io IO
if errors.As(networkError, &io) {
    timeout := io.Timeout()
    // ...
}

In this toy example we use errors.As detect if the underlying error
(which is NetworkError) satisfies the IO interface, and if so, populates
io with our error value, and call its Timeout() method.

After bumping the go directive version in go.mod to 1.21 the vet tool
is complaining about the ErrorAs assertion.

```
➜ go vet ./...
internal/assertions/assertions.go:208:6: second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type
```

The linter warning is a bit of a red-herring - in fact the `Target`
parameter for our `ErrorAs` assertion has been incorrect this whole time.
It should be `any`. Currently it is restricting types to be a concrete
type that implements the error interface, which is not a requirement of
`errors.As`.

In fact you can use errors.As to assert your err satisfies any interface
you choose - but the examples in the Go docs do not make this clear (imo).

For example you could have some error type:

```
type NetworkError interface {
    Error() error
    Timeout() bool
}
```

And you want to check if your error implements `Timeout()`, which you
can do using errors.As, e.g.

```
type IO interface {
    Timeout() bool
}

var io IO
if errors.As(networkError, &io) {
    timeout := io.Timeout()
    // ...
}
```

In this toy example we use `errors.As` detect if the underlying error
(which is NetworkError) satisfies the IO interface, and if so, populates
`io` with our error value, and call its `Timeout()` method.
@shoenig shoenig merged commit 7f5fe64 into main Apr 17, 2026
@shoenig shoenig deleted the better-error-as branch April 17, 2026 14:24
@alicebob
Copy link
Copy Markdown

This made me cleanup a bunch of ErrorAs into ErrorIs checks, which is what they should have been in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants