1

I am making a small function to check an error against some types and decide (depending on the error type) whether some retries are worth it.

I have created my own temporary interface to type assert all net/http errors that implement this interface (which however is unexported and thus I am declaring it my code as well)

type temporary interface {
    Temporary() bool
}

So, I want to retry when there is a net/http error implementing the temporary interface, as well in case the error is one of the following types: io.EOF, io.ErrUnexpectedEOF of ErrTimeoutExceeded

where

var ErrTimeoutExceeded = errors.New("timeout exceeded")

however the following switch statement


func isWorthRetrying(err error) bool {
    switch e := err.(type) {
    case temporary:
        return true
    case io.EOF:
        return true
    case io.ErrUnexpectedEOF:
        return true
    case ErrTimeoutExceeded:
        return true
    default:
        return false
    }
}

errors out in all statements (except the one type asserting against temporary)

with the error e.g.

io.EOF (type error) is not a type

What does this mean?

6
  • 4
    io.EOF is a value, not a type. switch e := err.(type) is a type switch for asserting the types in the cases. You are mixing up type switch and normal (expression) switch. You need two separate switches, one for types one for the error values. Commented Apr 6, 2020 at 12:53
  • Do a type switch with only one case for temporary, and in default do an expression switch where you check against the error values. Commented Apr 6, 2020 at 12:54
  • 2
    golang.org/ref/spec#Expression_switches and golang.org/ref/spec#Type_switches are two different switch statements. Commented Apr 6, 2020 at 12:55
  • ok thanks if you d like post it as a regular answer so that I can accept / upvote Commented Apr 6, 2020 at 13:03
  • 1
    user cd1 already posted an equivalent answer, you can accept that. Commented Apr 6, 2020 at 13:08

1 Answer 1

3

In your switch statement, you're checking against err.(type), which is a type. The values io.EOF, io.ErrUnexpectedEOF and ErrTimeoutExceeded aren't types, they're objects. You can't check if a type is an object (different things); however, you can check if an object is of a type.

You can use the following code to check for both scenarios:

func isWorthRetrying(err error) bool {
        switch err.(type) {
        case temporary:
                return true
        default:
                switch err {
                case io.EOF:
                        return true
                case io.ErrUnexpectedEOF:
                        return true
                case ErrTimeoutExceeded:
                        return true
                default:
                        return false
                }
        }
}

EDIT: thanks to Adrian's comment, we can also write this function using the new errors.Is, if you're using Go 1.13+:

func isWorthRetrying(err error) bool {
        switch err.(type) {
        case temporary:
                return true
        default:
                return errors.Is(err, io.EOF) ||
                        errors.Is(err, io.ErrUnexpectedEOF) ||
                        errors.Is(err, ErrTimeoutExceeded)
        }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Please take a look at the new error functionality introduced in Go 1.13 which simplifies and clarifies this sort of error checking code: golang.org/doc/go1.13#error_wrapping and golang.org/pkg/errors

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.