golang/go · info

context.Canceled

context.Canceled

Error message

context canceled

What it means

context.Canceled is the sentinel returned by Context.Err when the context was canceled for any reason other than its deadline expiring (deadline expiry returns DeadlineExceeded). It is a sentinel value, so callers compare with errors.Is; the Done() channel is closed at the same moment Err transitions from nil.

Source

Thrown at src/context/context.go:168

	// 	// instead of using this key directly.
	// 	var userKey key
	//
	// 	// NewContext returns a new Context that carries value u.
	// 	func NewContext(ctx context.Context, u *User) context.Context {
	// 		return context.WithValue(ctx, userKey, u)
	// 	}
	//
	// 	// FromContext returns the User value stored in ctx, if any.
	// 	func FromContext(ctx context.Context) (*User, bool) {
	// 		u, ok := ctx.Value(userKey).(*User)
	// 		return u, ok
	// 	}
	Value(key any) any
}

// Canceled is the error returned by [Context.Err] when the context is canceled
// for some reason other than its deadline passing.
var Canceled = errors.New("context canceled")

// DeadlineExceeded is the error returned by [Context.Err] when the context is canceled
// due to its deadline passing.
var DeadlineExceeded error = deadlineExceededError{}

type deadlineExceededError struct{}

func (deadlineExceededError) Error() string   { return "context deadline exceeded" }
func (deadlineExceededError) Timeout() bool   { return true }
func (deadlineExceededError) Temporary() bool { return true }

// An emptyCtx is never canceled, has no values, and has no deadline.
// It is the common base of backgroundCtx and todoCtx.
type emptyCtx struct{}

func (emptyCtx) Deadline() (deadline time.Time, ok bool) {
	return
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Check errors.Is(err, context.Canceled) and treat it as benign for client-initiated cancellation (do not log at error level).
  2. Distinguish from DeadlineExceeded to surface timeout vs explicit cancel differently in metrics.
  3. Ensure cleanup paths are ctx-independent so cancellation does not leak resources (use context.Background for teardown).
  4. If the cancellation is unexpected, audit parent contexts and any goroutine that holds a cancel func.

Example fix

// before: logging client disconnects as errors
if err := srv.Shutdown(ctx); err != nil {
    log.Printf("shutdown failed: %v", err)
}

// after: classify
if err := srv.Shutdown(ctx); err != nil {
    if errors.Is(err, context.Canceled) {
        return // client gave up; nothing to do
    }
    log.Printf("shutdown failed: %v", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-check needed: compare ctx.Err() before a long operation.
func runWithCtx(ctx context.Context, op func() error) error {
    if err := ctx.Err(); err != nil {
        return err // already canceled or expired
    }
    return op()
}

Type guard

func isCanceled(err error) bool {
    return errors.Is(err, context.Canceled)
}

Try / catch

if err := someCall(ctx); err != nil {
    if errors.Is(err, context.Canceled) {
        // Client/initiator gave up — usually benign.
        return nil
    }
    if errors.Is(err, context.DeadlineExceeded) {
        // Timeout — different observability signal.
    }
    return err
}

Prevention

When it happens

Trigger: Calling cancel() on a context obtained via WithCancel, WithCancelCause, or any derived context whose parent was canceled. Any blocking operation that accepts a context (DB query, HTTP request, gRPC call) will return this error when it observes the cancellation.

Common situations: Client disconnects on an HTTP server (request context canceled), goroutine supervision cancelling a worker, parent context cancellation propagating to children, or ctx.Cancel() called early on a timeout path that should have used WithTimeout instead.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/000285067bc1d728. Report an issue: GitHub.