
1 min read
Context package variables
The context package exports two variables: Variables var Canceled = errors.New("context canceled") Canceled is the error returned by [Context.Err] when the context is canceled for some reason other than its deadline passing. var DeadlineExceeded error = deadlineExceededError{} DeadlineExceeded is the error returned by [Context.Err] when the context is canceled due to its deadline passing. That’s it. These are the only two types of errors that a context’s Err() method is allowed to return.

2 min read
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.

2 min read
When not to use context values
Storing values in a context is quite flexible, but comes without strict type safety, and obscures the API. So what can we do about this? First, for type safety, we’re limited to runtime assertions: userID := ctx.Value(userIDKey).(string) But this can panic if we ever get an unexpected value (or even nil). So to make it safer, we can use the two-variable assignment form, which yields a bool indicating success: userID, ok := ctx.

2 min read
Context values and type safety
Last week I asked whether or not it’s a good idea to pass things like a user-scoped database handle or logger via a context value. Before I provide my direct answer, I want to take a short detour… Go is a (mostly) strictly-typed language. This gives us certain guarantees. When we have a variable of type int, we know it doesn’t contain the value "cow", because that’s not an integer.
Subscribe to Boldly Go: Daily
Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.
Unsure? Browse the archive.

2 min read
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.

2 min read
T.Context
After my last email, discussing context.TODO(), I got this question from Bruno Schaatsbergen: Thanks for the blog Jonathan, as always a pleasure to read. Regarding the last part on testing, any particular reason why you do not recommend using the new T.Context and B.Context methods? Great question! Go 1.24 added new methods to the testing package: T.Context, B.Context, and F.Context. These methods return a context which is canceled when the test, benchmark, or fuzz test, respectively, is canceled.

2 min read
context.TODO
Overview … Do not pass a nil Context, even if a function permits it. Pass context.TODO if you are unsure about which Context to use. Two pieces of advice in today’s section. I’m going to tackle them in reverse, though. Use context.TODO() if you are unsure which Context to use. Functionally context.TODO() is identical to context.Background(). In fact, the only difference between the two, is their implementation of the String() method, as we can see by reading the source:

3 min read
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.

4 min read
What's wrong with this code? ANSWERED!
On Friday, I shared a short code snippet, and asked how it could be improved. If you missed it, go read the challenge now then come back. I got a good number of responses, so today I’m going to share a few of them, and offer my own answer. First off, Jim Kalafut, and several others, the code I shared. One line was return nil, but should have been return decodedBytes, nil.

1 min read
What's wrong with this code?
Today I want to share a bit of code I found in the wild, and challenge you to improve it. First off, let me make it clear that this code “works”. It has unit tests, and the tests all pass correctly. So I’m not looking for bugs, per se. func decodeString(encoded string) ([]byte, error) { var decodedBytes []byte var err error trimmed := strings.TrimRight(encoded, "=") decodedBytes, err = base64.StdEncoding.DecodeString(trimmed) if err !

2 min read
Context rules
Overview … Programs that use Contexts should follow these rules to keep interfaces consistent across packages and enable static analysis tools to check context propagation: Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. This is discussed further in https://go.dev/blog/context-and-structs. We’ve already discussed how the proliferation of the ctx context.Context argument can start to look more cluttered than my desk on a Friday afternoon.