Go

What does this print? (WithTimeoutCause and its cancel function)

Question 266HardGo 1.22 to 1.25
var errSlow = errors.New("payment provider slow")

func main() {
	ctx, cancel := context.WithTimeoutCause(context.Background(), time.Hour, errSlow)
	cancel()
	fmt.Println(ctx.Err())
	fmt.Println(context.Cause(ctx))

	ctx2, cancel2 := context.WithTimeoutCause(context.Background(), time.Millisecond, errSlow)
	defer cancel2()
	<-ctx2.Done()
	fmt.Println(ctx2.Err())
	fmt.Println(context.Cause(ctx2))
}

Output:

context canceled
context canceled
context deadline exceeded
payment provider slow

WithTimeoutCause/WithDeadlineCause (Go 1.21) attach the cause only to the timer firing. The cancel function they return is a plain CancelFunc with no argument, so calling it early records Canceled as both the error and the cause.

Gotcha: if you want a custom cause for manual cancellation and for timeout, layer them: ctx, cancel := context.WithCancelCause(parent), then ctx, stop := context.WithTimeoutCause(ctx, d, errSlow). Call cancel(myErr) for manual aborts, and defer stop() as well as defer cancel(nil).

More on Context

All 35 Context questions