Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Returning pointers to custom errors causes a non-recovered panic #806

Open
barak-bem opened this issue Mar 12, 2025 · 1 comment
Open

Comments

@barak-bem
Copy link

Hello! My team recently ran into an issue where returning a nil pointer to a custom error (which we use to attach our own business context) in a Work(...) function caused our whole service to die due to a panic in job_executor.go. We heavily use the custom fields in our error handler.

This can be reproduced like so:

type CustomError {
    InternalErr error
}

type JobWorker struct {
    river.WorkerDefaults[workers.JobWorkerArgs
}

func (jw *JobWorker) Work(ctx context.Context, job *river.Job[workers.JobWorkerArgs]) error {
    var customErr *CustomError
    return customErr
}

Totally aware that this is a classic typed nil issue! However I believe it's unfortunate that this can compile and take down the server with very little observability.

We fixed this by adding a check everywhere that looks like this:

if customErr != nil {
     return customErr
}

return nil

Would it be possible to either:

  1. Support pointers to custom errors (this is preferred by our team)
  2. Recover from the panics within the job executor to avoid bringing down the service
@brandur
Copy link
Contributor

brandur commented Mar 15, 2025

@barak-bem Yeah, man I totally understand that this is annoying as heck. This problem is such a common misunderstanding in Go that they actually added a FAQ for it:

https://go.dev/doc/faq#nil_error

Naturally, it's condescending written and paraphrased basically says "Go is designed perfectly, and some small-minded individuals just don't get it". I would've said: if this so many people are running into trouble with this, it's obviously not a problem with them, but rather a problem with the language's design, and it should be fixed. Alas, it's unlikely to happen at this point.

Regarding River though: given this is much more fundamental problem in Go, I'm not sure that we should have special handling for it. If anything, it should be fixed at a lower level for everyone.

For now, I think the best we could suggest is similar to the code blocks in that FAQ. Instead of writing this:

func returnsError() error {
    var p *MyError = nil
    if bad() {
        p = ErrBad
    }
    return p // Will always return a non-nil error.
}

Write this instead:

func returnsError() error {
    if bad() {
        return ErrBad
    }
    return nil
}

It'd be nice to add a safety hedge or something I suppose, but I'm not even sure it's possible to do so without the use of reflection (i.e. open the pointer to a custom type and check the nil value within).

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

No branches or pull requests

2 participants