#4563·fiber

v4: stop implementing context.Context on Ctx

Author: ReneWerner87Created Jul 28, 2026Updated Aug 5, 2026

Problem

ctx.go:38 asserts that *DefaultCtx satisfies context.Context:

go
_ context.Context = (*DefaultCtx)(nil) // Compile-time check

DefaultCtx is recycled through a sync.Pool and mutated during the request. A context.Context is meant to be an immutable value that you derive from and hand across goroutine boundaries. Those two models do not fit, and the mismatch keeps producing bugs rather than one bug:

  • Deadline(), Done() and Err() can only ever be no-ops. A non-nil Done() makes context.propagateCancel and database/sql spawn watcher goroutines that retain the pooled *DefaultCtx past release(), and reading Err() back through the recycled object panics with context: internal error: missing cancel error in a goroutine Fiber cannot recover. See #4560 for the full derivation.
  • Value() reads the fasthttp userValues slice that Locals() writes, so it is not safe for concurrent use, which the interface requires.
  • Users write db.QueryContext(c, ...) because the compiler accepts it, and get no cancellation. It is silent, and it is the natural thing to write. #4335 is one report of this; the docs were teaching the same pattern until #4560.

Every fix so far has been a workaround for the assertion above.

Proposal for v4

Drop the assertion and stop implementing context.Context on Ctx. c.Context() already returns a real context.Context and is the documented way to get cancellation, deadlines, and something safe to use after the handler returns.

The payoff is that the compiler rejects c wherever a context.Context is expected, so the entire class of "it compiled but nothing was ever canceled" disappears at the call site instead of in production.

Migration

Mechanical and greppable: f(c) becomes f(c.Context()) wherever f takes a context.Context. Worth a note in the v4 migration guide with exactly that sentence.

Open questions

  • Keep Value() as a plain method for Locals interop, or drop it too?
  • Is there a use for a small adapter (c.AsContext()), or is c.Context() enough?

Refs #4560, #4335