Cancelation causes

March 25, 2025

We’ve seen that we can cancel contexts in a few ways–explicitly, or via timeouts. And that canceling a parent context also cancels all of its children.

But in all of these cases we get only two possible error values: context.Canceled or context.DeadlineExceeded. What if you wish to express additional details about a cancelation? This is where the concept of a ‘cause’ comes into play…

Overview

The WithCancelCause, WithDeadlineCause, and WithTimeoutCause functions return a CancelCauseFunc, which takes an error and records it as the cancellation cause. Calling Cause on the canceled context or any of its children retrieves the cause. If no cause is specified, Cause(ctx) returns the same value as ctx.Err().

These *Cause variations of context cancelation allow you to provide an arbitrary error as the “cause” of the cancelation. This can then later be retrieved from the canceled context. Note that this “cause” error is still indepenent from the original context.Canceled or context.DeadlineExceeded error value. You must expressly check for the “cause” to get it. And we’ll talk more about how to do that, and the implications, when we get to those specific functions.


Share this

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

Unsure? Browse the archive .

Related Content


Concurrent use of contexts

Overview … The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines. Contexts are built using layers. Every time you call one of the context.With* functions, the orginal context is wrapped in a new layer. This is the “magic” that makes contexts concurrency safe by design–they’re never mutated once they’re created. ctx := context.Background() // Create an original context ctx, cancel = context.


Context abuse

We’re nearly through the overview of the context package, when we come across this seemlingly straightforward sentence: Overview … Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions. But is that really so straight forward? Let’s consider some examples. Let’s first tackle what probably is straight-forward: For garden variety optional parameters, context is the wrong tool! Do this: // Connect connects to the service using the provided host and port, or the // default host and/or port if omitted.


Context arguments

Overview … The Context should be the first parameter, typically named ctx: func DoSomething(ctx context.Context, arg Arg) error { // ... use ctx ... } This short sentence includes two “rules”. Let’s talk about both, why they exist, and when to (possibly) violate them. Context should be the first parameter. Why this is a rule is probably a lot less important than following the rule. But let’s consider the why anyway.

Get daily content like this in your inbox!

Subscribe