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
- Q264What values can ctx.Err() return, and how should you check them?
- Q265What is WithCancelCause, and how does ctx.Err() differ from context.Cause(ctx)?
- Q267Why should context keys use an unexported custom type instead of a string? Show the idiomatic pattern.
- Q268What does this print? (context value keys)
- Q269How is Value lookup implemented, and what are its performance implications?
- Q270What belongs in context values and what doesn't?