Skip to main content Farid Yusof's Blog

Sentinel Error

I was working on a project where I need to check on certain errors that return from a deep, deep function.

The deepest function was calling a third party API. Fortunately, the third party package that I was using is pretty following ‘single responsibility principle’.

Ah, this is great! Since the function purpose is to wait until some capacity is ready on the provider side, I can just check on the error the function returns.

Below is the current implementation before I refactor it.

go code snippet start

someWaitingProcess, err := provider.WaitUntilReady()
if err != nil {
    return err
}

go code snippet end

In my thought process, I knew that the error is related to problem waiting for capacity. However, I can’t return the error directly.

On the upper layer, I need to check on the error and return a specific error, but I can’t just do something like below:

go code snippet start

theFunc, err := functionThatCallsWaitUntilReady()
if err != nil {
    if err.Error() == "wait until ready error" {
        // handle the error
    }

    return err
}

go code snippet end

Why? There’s a possibility that the error returned from the deepest function is being changed by the third party package. Possible!

The easiest way to handle this is to create a sentinel error.

go code snippet start

var ErrWaitUntilReady = errors.New("wait until ready error")

someWaitingProcess, err := provider.WaitUntilReady()
if err != nil {
    return ErrWaitUntilReady
}

go code snippet end

Now, I can refactor the code to something like below:

go code snippet start

someWaitingProcess, err := provider.WaitUntilReady()
if err != nil {
    if errors.Is(err, ErrWaitUntilReady) {
        // handle the error
    }
}

go code snippet end

I think this is a good way to handle this kind of problem.

If this is helpful, feel free to share it with others. Just writing it down so I won’t forget. 😃😃😃

comments powered by Disqus