How to use errors.As with sentinel errors?

182 views
Skip to first unread message

cpu...@gmail.com

unread,
Aug 2, 2021, 4:02:11 AM8/2/21
to golang-nuts
Consider this example: https://play.golang.org/p/16cU0kc8Lku, basically

var Err = errors.New("sentinel")
err := errors.New("foo")
if errors.As(err, &Err) {
  fmt.Println("why?")
}

I'm wondering why this matches the sentinel error, or rather how to properly use sentinel errors. errors.As says "An error matches target if the error's concrete value is assignable to the value pointed to by target". This seems to be the case here (both are of type error).

However, if thats the case, how should I construct a sentinel error that would be usable with errors.As? I don't want to rely on errors.Is as errors could be wrapped. So to "break" the assignability- would that mean that I'd need to define sentinel errors as e.g. struct types?

Seem's I'm still lacking the level of understanding for go errors that I'd aspire to :/

Cheers,
Andi

cpu...@gmail.com

unread,
Aug 2, 2021, 4:08:03 AM8/2/21
to golang-nuts
Ah, think I found it: https://blog.golang.org/go1.13-errors says:

In the simplest case, the errors.Is function behaves like a comparison to a sentinel error, and the errors.Asfunction behaves like a type assertion. When operating on wrapped errors, however, these functions consider all the errors in a chain. 

So I should just use errors.Is here... Sorry for the confusion!

Axel Wagner

unread,
Aug 2, 2021, 4:09:48 AM8/2/21
to cpu...@gmail.com, golang-nuts
On Mon, Aug 2, 2021 at 10:02 AM cpu...@gmail.com <cpu...@gmail.com> wrote:
Consider this example: https://play.golang.org/p/16cU0kc8Lku, basically

var Err = errors.New("sentinel")
err := errors.New("foo")
if errors.As(err, &Err) {
  fmt.Println("why?")
}

I'm wondering why this matches the sentinel error

Because both are of type `*errors.errorString`, so the types match and it copies over the value.
Arguably, `errors.errorString` should implement `As()` and return `false`, unless the pointers match. I suggest filing an issue.
 
or rather how to properly use sentinel errors.

Use `errors.Is`, instead of `errors.As`.
 
However, if thats the case, how should I construct a sentinel error that would be usable with errors.As? I don't want to rely on errors.Is as errors could be wrapped.

And? They can be wrapped for `As` as well. `errors.As` is only useful if you want to get additional information out of the error (e.g. it's useful for use with `os.PathError`). By definition, it's pointless to use it with a sentinel error.
 
So to "break" the assignability- would that mean that I'd need to define sentinel errors as e.g. struct types?

Seem's I'm still lacking the level of understanding for go errors that I'd aspire to :/

Cheers,
Andi

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4d8969b4-dd5a-4834-893b-3e01174570bfn%40googlegroups.com.

Andreas Götz

unread,
Aug 2, 2021, 12:30:04 PM8/2/21
to golang-nuts
> Because both are of type `*errors.errorString`, so the types match and it copies over the value.
Arguably, `errors.errorString` should implement `As()` and return `false`, unless the pointers match. I suggest filing an issue.

Will do. It could also be a vet check to highlight errors.As used on sentinel errors which is most likely wrong as I demonstrated.

Andreas Götz

unread,
Aug 4, 2021, 3:25:02 AM8/4/21
to golang-nuts
Reply all
Reply to author
Forward
0 new messages