Skip to content

🐛 bug: avoid panic when reading released Fiber context values#4271

Merged
ReneWerner87 merged 10 commits into
mainfrom
fix-panic-in-valuefromcontext-for-fiber
May 15, 2026
Merged

🐛 bug: avoid panic when reading released Fiber context values#4271
ReneWerner87 merged 10 commits into
mainfrom
fix-panic-in-valuefromcontext-for-fiber

Conversation

@gaby
Copy link
Copy Markdown
Member

@gaby gaby commented May 10, 2026

Motivation

  • Restore the nil-safe semantics for context value lookups so that retained/released fiber.Ctx instances cannot cause a panic when helpers call ValueFromContext after ReleaseCtx.

Description

  • Prefer Value(key) over Locals(key) when a Fiber-like context exposes both by adding a fiberValueContext interface and dispatching to Value first in internal/contextvalue/contextvalue.go.
  • Add a regression test in helpers_test.go that asserts ValueFromContext does not panic and returns (zero, false) when called with a released fiber.Ctx.

@gaby gaby added the aardvark label May 10, 2026
Copilot AI review requested due to automatic review settings May 10, 2026 15:29
@gaby gaby requested a review from a team as a code owner May 10, 2026 15:29
@gaby gaby requested review from ReneWerner87, efectn and sixcolors May 10, 2026 15:29
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Reorders Value[T] lookup precedence to check *fasthttp.RequestCtx first (then context.Context, valueContext, fiber locals, and userValueContext), adds tests verifying locals/value access after a released Fiber ctx does not panic and returns no value, and guards DefaultReq.Locals for nil fasthttp backing.

Changes

Context value lookup precedence and released-ctx safety

Layer / File(s) Summary
Value[T] lookup precedence
internal/contextvalue/contextvalue.go
Reorders type-switch: check *fasthttp.RequestCtx (UserValue) first, then context.Context (Value), then valueContext (Value), then fiberLocalContext (Locals), then userValueContext (UserValue).
Post-release locals/value tests
helpers_test.go, ctx_test.go
Adds subtests that acquire a fiber.Ctx/CustomCtx, set a local, call app.ReleaseCtx(c), then assert ValueFromContext/ctx.Locals does not panic and returns no value.
Defensive DefaultReq.Locals
req.go
DefaultReq.Locals returns the provided value (if any) when r.c.fasthttp is nil, avoiding panics when accessed after ctx release.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • gofiber/fiber#3720: Related changes touching context value resolution and stdlib context interop.
  • gofiber/fiber#3382: Related work on context.Context.Value integration with Fiber locals.

Suggested reviewers

  • sixcolors
  • efectn
  • ReneWerner87

Poem

🐰 I hop through switches, checking each place,
fasthttp first, then stdlib's embrace.
A Ctx released, I still give a glance,
No panic, no value — a safe little dance. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description provides clear motivation and technical details of the fix, but does not address most of the template's required checklist items like benchmarks, documentation updates, changelog entries, or test validation status. Complete the checklist by confirming test coverage, documentation updates if needed, and any performance considerations for this bug fix.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: avoiding panics when reading released Fiber context values, which aligns with the changeset's core purpose.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-panic-in-valuefromcontext-for-fiber

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.26%. Comparing base (c48bbc2) to head (22d3321).
⚠️ Report is 24 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4271      +/-   ##
==========================================
+ Coverage   91.21%   91.26%   +0.05%     
==========================================
  Files         130      130              
  Lines       12760    12767       +7     
==========================================
+ Hits        11639    11652      +13     
+ Misses        709      704       -5     
+ Partials      412      411       -1     
Flag Coverage Δ
unittests 91.26% <100.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores nil-safe context value lookups by ensuring ValueFromContext won’t panic when called on a released fiber.Ctx (e.g., after ReleaseCtx), which is important for middleware/helpers that may retain a context reference beyond its lifetime.

Changes:

  • Updated internal/contextvalue.Value to prefer a Fiber context’s Value(key) method over Locals(key) when both are available, avoiding nil dereferences after context release.
  • Added a regression test to ensure ValueFromContext does not panic and returns (zero, false) when invoked on a released fiber.Ctx.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
internal/contextvalue/contextvalue.go Adds a Fiber-specific interface and dispatches to Value() first to avoid panics on released contexts.
helpers_test.go Adds a regression subtest covering ValueFromContext behavior after ReleaseCtx.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new fiberValueContext interface and updates the Value function to prioritize it, ensuring nil-safe access to context values after a Fiber context has been released. A new test case was added to verify that accessing values from a released context does not cause a panic. The reviewer suggested a maintainability improvement to use the existing valueContext interface at the top of the type switch instead of introducing a new interface to achieve the same result.

Comment thread internal/contextvalue/contextvalue.go Outdated
@gaby
Copy link
Copy Markdown
Member Author

gaby commented May 10, 2026

@copilot Prioritizing fiberValueContext here correctly ensures that the nil-safe Value method is used for Fiber contexts, preventing panics after context release. As a minor improvement for maintainability, consider if the existing valueContext interface could be moved to the top of the switch instead of introducing the new fiberValueContext interface. This would achieve the same result for DefaultCtx while also simplifying the handling of context.Context and other types that implement Value.

If this apply, make the changes.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/contextvalue/contextvalue.go (1)

26-31: 💤 Low value

The *fasthttp.RequestCtx concrete case is redundant but intentional.

Both the concrete *fasthttp.RequestCtx case (lines 26-28) and the userValueContext interface case (lines 29-31) call UserValue(key) identically. Since *fasthttp.RequestCtx implements the userValueContext interface, the interface case would handle it; however, the concrete type check is a performance optimization to avoid the overhead of interface assertion. This appears to be intentional design (documented in helpers.go as an explicitly supported context type) rather than legacy code. If clarity is desired, consider adding a comment explaining the performance rationale for keeping the concrete case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/contextvalue/contextvalue.go` around lines 26 - 31, The concrete
type switch case for *fasthttp.RequestCtx duplicates the userValueContext
handling but was left intentionally as a performance optimization; add a short
comment above the *fasthttp.RequestCtx case explaining that *fasthttp.RequestCtx
implements userValueContext and that the concrete type check is kept to avoid
the extra interface assertion overhead (referencing UserValue and the
userValueContext interface), and optionally link or mention helpers.go where
this explicit support is documented so future readers understand it’s
deliberate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/contextvalue/contextvalue.go`:
- Around line 26-31: The concrete type switch case for *fasthttp.RequestCtx
duplicates the userValueContext handling but was left intentionally as a
performance optimization; add a short comment above the *fasthttp.RequestCtx
case explaining that *fasthttp.RequestCtx implements userValueContext and that
the concrete type check is kept to avoid the extra interface assertion overhead
(referencing UserValue and the userValueContext interface), and optionally link
or mention helpers.go where this explicit support is documented so future
readers understand it’s deliberate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ca1c95f5-88e6-4dd0-a752-7d1ae4db42fa

📥 Commits

Reviewing files that changed from the base of the PR and between a7dda29 and bf540f3.

📒 Files selected for processing (1)
  • internal/contextvalue/contextvalue.go

Copy link
Copy Markdown
Contributor

Copilot AI commented May 10, 2026

@copilot Prioritizing fiberValueContext here correctly ensures that the nil-safe Value method is used for Fiber contexts, preventing panics after context release. As a minor improvement for ma...

Applied in e0d04b6. I removed the extra fiberValueContext interface and now dispatch through the existing valueContext, while still keeping *fasthttp.RequestCtx ahead of the interface case for lint-compliant specificity.

Copilot finished work on behalf of gaby May 10, 2026 16:08
@gaby
Copy link
Copy Markdown
Member Author

gaby commented May 10, 2026

@copilot do not remove the case:

case context.Context:
    val, ok := typed.Value(key).(T)
    return val, ok

We need to support fiber ctx, fasthttp request ctx, and context.Context

Copy link
Copy Markdown
Contributor

Copilot AI commented May 10, 2026

@copilot do not remove the case:

...

Restored the explicit context.Context case in a51620e so fiber.Ctx, *fasthttp.RequestCtx, and context.Context all remain directly supported.

Copilot finished work on behalf of gaby May 10, 2026 16:27
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
internal/contextvalue/contextvalue.go (2)

21-21: ⚡ Quick win

Clarify documentation to reflect support for standard context.Context.

The comment states "supported Fiber context types" but the function also handles standard context.Context (line 27-29), which is not Fiber-specific.

📝 Proposed documentation fix
-// Value retrieves a value stored under key from supported Fiber context types.
+// Value retrieves a value stored under key from supported context types (Fiber contexts, context.Context, and fasthttp.RequestCtx).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/contextvalue/contextvalue.go` at line 21, Update the doc comment for
the Value function to reflect that it supports both Fiber context types and the
standard context.Context: locate the Value function in contextvalue.go and
change the sentence "Value retrieves a value stored under key from supported
Fiber context types." to mention support for standard context.Context as well
(e.g., "Value retrieves a value stored under key from supported Fiber context
types and the standard context.Context"), ensuring the comment references the
Value function name so readers know which function the doc covers.

24-38: ⚡ Quick win

Consider the author's suggestion to reorder valueContext before context.Context for clarity.

The current order places context.Context (line 27-29) before valueContext (line 30-32). Both cases call .Value(key), so this is functionally equivalent. However, as noted in the PR comments, moving valueContext to be checked first would make the intent more explicit: prioritize types with a Value method (including Fiber's DefaultCtx and other contexts) before falling back to Locals.

The current placement of fiberLocalContext (line 33-35) after both context.Context and valueContext is correct and prevents panics on released contexts.

Trade-offs:

  • Current order (context.Context first): Standard library interface is checked first, which may be more intuitive for readers familiar with Go's context package.
  • Suggested order (valueContext first): Makes the "prefer Value over Locals" design more explicit and aligns with the PR's intent to avoid Locals on released contexts.

Since both approaches are safe and the author explicitly suggested this reordering, moving valueContext before context.Context would improve maintainability and align with the PR's stated goal.

♻️ Proposed reordering to prioritize valueContext
 func Value[T any](ctx, key any) (T, bool) {
 	switch typed := ctx.(type) {
 	case *fasthttp.RequestCtx:
 		val, ok := typed.UserValue(key).(T)
 		return val, ok
+	case valueContext:
+		val, ok := typed.Value(key).(T)
+		return val, ok
 	case context.Context:
 		val, ok := typed.Value(key).(T)
 		return val, ok
-	case valueContext:
-		val, ok := typed.Value(key).(T)
-		return val, ok
 	case fiberLocalContext:
 		val, ok := typed.Locals(key).(T)
 		return val, ok
 	case userValueContext:
 		val, ok := typed.UserValue(key).(T)
 		return val, ok
 	default:
 		var zero T
 		return zero, false
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/contextvalue/contextvalue.go` around lines 24 - 38, Reorder the type
switch cases so valueContext is checked before context.Context: in the switch
handling *fasthttp.RequestCtx, context.Context, valueContext, fiberLocalContext,
userValueContext, move the case valueContext block to appear immediately after
the *fasthttp.RequestCtx case and before the context.Context case (leave
fiberLocalContext and the other cases in place) so the code still uses
.Value(key) for valueContext prior to falling back to the generic
context.Context case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/contextvalue/contextvalue.go`:
- Line 21: Update the doc comment for the Value function to reflect that it
supports both Fiber context types and the standard context.Context: locate the
Value function in contextvalue.go and change the sentence "Value retrieves a
value stored under key from supported Fiber context types." to mention support
for standard context.Context as well (e.g., "Value retrieves a value stored
under key from supported Fiber context types and the standard context.Context"),
ensuring the comment references the Value function name so readers know which
function the doc covers.
- Around line 24-38: Reorder the type switch cases so valueContext is checked
before context.Context: in the switch handling *fasthttp.RequestCtx,
context.Context, valueContext, fiberLocalContext, userValueContext, move the
case valueContext block to appear immediately after the *fasthttp.RequestCtx
case and before the context.Context case (leave fiberLocalContext and the other
cases in place) so the code still uses .Value(key) for valueContext prior to
falling back to the generic context.Context case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4e887eae-f438-49fe-8a26-10c9a2d73d05

📥 Commits

Reviewing files that changed from the base of the PR and between e0d04b6 and a51620e.

📒 Files selected for processing (1)
  • internal/contextvalue/contextvalue.go

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown
Member

@ReneWerner87 ReneWerner87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diagnosis is right and the patch works (CI is green, regression test covers the panic path). Two suggestions, the first one is the load-bearing one.

1. Consider fixing the root cause in DefaultReq.Locals instead

The asymmetry between DefaultCtx.Value (ctx.go:625, nil-safe via if c.fasthttp == nil { return nil }) and DefaultReq.Locals (req.go:703, no guard) is the actual bug. Hardening only the helper means:

  • every other caller of c.Locals(key) after ReleaseCtx still panics: middleware (session, requestid, ...), user code, tests; the helper reorder only protects ValueFromContext.
  • the type-switch reorder becomes load-bearing in a non-obvious way; a future contributor sorting cases by specificity reintroduces the bug.

A minimal alternative, applied at the symptom source:

func (r *DefaultReq) Locals(key any, value ...any) any {
    if r.c.fasthttp == nil {
        if len(value) > 0 {
            return value[0]
        }
        return nil
    }
    if len(value) == 0 {
        return r.c.fasthttp.UserValue(key)
    }
    r.c.fasthttp.SetUserValue(key, value[0])
    return value[0]
}

This mirrors Value's pattern, fixes every caller, and makes the helper reorder optional (you can keep it for clarity or revert to the previous order without functional impact).

2. If you keep the reorder, document why

The order in the type switch is now load-bearing for nil-safety. Without a comment the next contributor who thinks "most specific case first" can revert it. See inline.

3. Test could carry a tiny bit more weight

The regression test only covers *DefaultCtx after release with a string value. Adding a fiber.CustomCtx-released case and a pre-release sanity check (that key is retrievable before ReleaseCtx) would document the contract more fully and protect against accidental CustomCtx behavior changes from the reorder. See inline.

Nothing here is blocking; CI is green and Codecov is at 100% for modified lines.

Comment thread internal/contextvalue/contextvalue.go Outdated
Comment thread internal/contextvalue/contextvalue.go
Comment thread helpers_test.go
@gaby
Copy link
Copy Markdown
Member Author

gaby commented May 13, 2026

@copilot Please address all the review comments.

Copy link
Copy Markdown
Contributor

Copilot AI commented May 13, 2026

@copilot Please address all the review comments.

Addressed the review feedback across bbf6194 and 22d3321; the branch now fixes released Locals at the source, refreshes the docs, and strengthens the released-context tests.

Copilot finished work on behalf of gaby May 13, 2026 03:34
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 22d3321 Previous: 33b7fd4 Ratio
Benchmark_NewError (github.com/gofiber/fiber/v3) 61.77 ns/op 24 B/op 1 allocs/op 37.8 ns/op 24 B/op 1 allocs/op 1.63
Benchmark_NewError (github.com/gofiber/fiber/v3) - ns/op 61.77 ns/op 37.8 ns/op 1.63

This comment was automatically generated by workflow using github-action-benchmark.

@ReneWerner87 ReneWerner87 merged commit 7e4493e into main May 15, 2026
20 of 21 checks passed
@ReneWerner87 ReneWerner87 deleted the fix-panic-in-valuefromcontext-for-fiber branch May 15, 2026 10:20
@github-project-automation github-project-automation Bot moved this to Done in v3 May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants