Go Fundamentals - Sample

Table of Contents

Chapter 12.9: Context Errors

In a complex system, or even in a small one, when a context.Context is cancelled, we need a way to know what caused the cancellation. It is possible that context.Context was cancelled by a context.CancelFunc successfully, if it was cancelled because it timed out, or some other reason.

The context.Context.Err method, Listing 12.1 returns the error that caused the context to be cancelled.

$ go doc context.Context.Err

package context // import "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:
	// Canceled if the context was canceled
	// or DeadlineExceeded if the context's deadline passed.
	// After Err returns a non-nil error, successive calls to Err return the same error.
	Err() error
}

--------------------------------------------------------------------------------
Go Version: go1.23.0

Listing 12.1: The context.Context.Err method.

Context Cancelled Error

The context package defines two different error variables that can be used to check an error that was returned from context.Context.Err method.

The first is context.Canceled, Listing 12.2, which is returned when the context is cancelled through the use of a context.CancelFunc function. This error is considered to indicate a "successful" cancellation.

$ go doc context.Canceled

package context // import "context"

var Canceled = errors.New("context canceled")
    Canceled is the error returned by [Context.Err] when the context is
    canceled.

--------------------------------------------------------------------------------
Go Version: go1.23.0

Listing 12.2: The context.Canceled error.

Consider Listing 12.3. When we first check the context.Context.Err method, it returns nil. After we call the context.CancelFunc function provided by context.WithCancel, the context.Context.Err method returns a context.Canceled error.

func main() {

	// create a background context
	ctx := context.Background()

	// wrap the context with a
	// cancellable context
	ctx, cancel := context.WithCancel(ctx)

	// check the error:
	//	
	fmt.Println("ctx.Err()", ctx.Err())

	// cancel the context
	cancel()

	// check the error:
	//	context.Canceled
	fmt.Println("ctx.Err()", ctx.Err())

	// check the error again:
	//	context.Canceled
	fmt.Println("ctx.Err()", ctx.Err())
}

$ go run .

ctx.Err() <nil>
ctx.Err() context canceled
ctx.Err() context canceled

--------------------------------------------------------------------------------
Go Version: go1.23.0
Listing 12.3: Checking for cancellation errors.

As we can see from the output in Listing 12.3, repeated calls to the context.Context.Err method return the same context.Canceled error.

Context Deadline Exceeded Error

When a context.Context is cancelled due to a deadline, or timeout, being exceeded, the context.Context.Err method returns a context.DeadlineExceeded error, Listing 12.4.

$ go doc context.DeadlineExceeded

package context // import "context"

var DeadlineExceeded error = deadlineExceededError{}
    DeadlineExceeded is the error returned by [Context.Err] when the context's
    deadline passes.

--------------------------------------------------------------------------------
Go Version: go1.23.0

Listing 12.4: The context.DeadlineExceeded error.

Consider Listing 12.5. We create a context.Context that will self cancel after 1 second. When we check context.Context.Err method, before the context.Context times out, it returns nil.

func main() {

	// create a background context
	ctx := context.Background()

	// wrap the context that will
	// self cancel after 10 milliseconds
	ctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)
	defer cancel()

	// check the error:
	//	
	fmt.Println("ctx.Err()", ctx.Err())

	// wait for the context to self cancel
	<-ctx.Done()

	// check the error:
	//	context.Canceled
	fmt.Println("ctx.Err()", ctx.Err())

	// check the error again:
	//	context.DeadlineExceeded
	fmt.Println("ctx.Err()", ctx.Err())
}

$ go run .

ctx.Err() <nil>
ctx.Err() context deadline exceeded
ctx.Err() context deadline exceeded

--------------------------------------------------------------------------------
Go Version: go1.23.0
Listing 12.5: Checking for deadline exceeded errors.

As we can see from the output, the context.Context times out after the specified time, and the context.Context.Err method returns a context.DeadlineExceeded error.