Context errors

May 21, 2025

type Context

type Context interface {
…
	// If Done is not yet closed, Err returns nil.
	// If Done is closed, Err returns a non-nil error explaining why:
	// DeadlineExceeded if the context's deadline passed,
	// or Canceled if the context was canceled for some other reason.
	// After Err returns a non-nil error, successive calls to Err return the same error.
	Err() error

Done() (covered yesterday) and Err() (today) are the two methods you’ll virtually alway use when writing code to honor context cancelations. So although we’ve already touched on the important behavior if this method, it never hurts to do a short recap.

First, Err() returns nil if the context is still live (not yet canceled). This actually means that in some contexts, you can simply use Err() and avoid the Done() method entirely. For example, yeterday’s example that simply checks for context cancelation without blocking:

select {
case <-ctx.Done():
	return ctx.Err():
default:
}

could be be re-written as:

if err := ctx.Err(); err != nil {
	return err
}

Other than that, the most important thing to note is that Err() only ever returns two possible (non-nil) values: context.Canceled or context.DeadlineExceeded. This means two things;

  1. As the consumer of such an error, you never need to handle other cases.
  2. If you’re creating a custom implementation of the context.Context type, you must only ever return those two error values. Anything else could break consumers that follow the actual spec.

If you want to express some other error value, use the context.WithCancelCause or one of the related functions discussed in the past.


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe