Skip to content

Conversation

@gaby
Copy link
Member

@gaby gaby commented Feb 7, 2026

Motivation

  • Prevent session-object leaks and panics by ensuring acquired Session objects are always returned to the pool on every terminal/error path.
  • Let middleware initialization failures be handled by the configured error handler instead of panicking and ensure middleware objects are released on init failure.
  • Add regression coverage for lifecycle/error paths so release/save semantics are exercised and protected from regressions.

Description

  • Make (*Middleware).initialize return error and update NewWithStore to invoke the configured ErrorHandler or DefaultErrorHandler on init failures while releasing the middleware and returning the original error only when no response status was written.
  • Add finalizeSession() which conditionally calls saveSession() (skips when destroyed) and always calls releaseSession(m.Session) exactly once to guarantee object lifecycle cleanup.
  • Harden Store.getSession to call sess.Release() before returning when sess.Reset() fails on absolute-expiry, and change Store.GetByID to always sess.Release() before returning ErrSessionIDNotFoundInStore after attempting sess.Destroy().
  • Audit nearby early-return branches around acquireSession() for balanced Release() calls and add targeted tests for the new behaviors in middleware/session/middleware_test.go and middleware/session/store_test.go.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 7, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch update-session-middleware-to-fail-gracefully

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gaby, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the reliability and resource management of the session middleware. It focuses on preventing session object leaks and application panics by ensuring that session objects are always properly released back to their pool, even when errors occur during initialization or session lifecycle events. The changes centralize session finalization logic and harden error paths within the session store, leading to a more stable and predictable session management system.

Highlights

  • Robust Error Handling for Session Middleware Initialization: The session middleware's initialization process now gracefully handles errors by invoking a configured error handler and ensuring proper resource release, preventing panics and improving stability.
  • Centralized Session Lifecycle Management: A new finalizeSession() method has been introduced to ensure that acquired session objects are consistently saved (if not destroyed) and always returned to the pool, preventing session object leaks.
  • Hardened Session Store Error Paths: The Store.getSession and Store.GetByID methods have been updated to explicitly release session objects back to the pool in various error and expiry scenarios, such as when sess.Reset() fails or an expired session is destroyed.
  • Comprehensive Test Coverage: New unit tests have been added for both middleware.go and store.go to specifically cover the new error handling, session finalization logic, and session release behaviors in edge cases.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • middleware/session/middleware.go
    • Modified NewWithStore to catch initialization errors from m.initialize, call the configured ErrorHandler, and release the middleware object.
    • Changed (*Middleware).initialize to return an error instead of panicking, allowing for controlled error propagation.
    • Introduced (*Middleware).finalizeSession to encapsulate the logic for conditionally saving a session and always releasing the session object.
  • middleware/session/middleware_test.go
    • Added failingStorage and lifecycleStorage structs to simulate storage errors and track lifecycle calls in tests.
    • Introduced new tests for Test_Session_Middleware_InitializeError_WithCustomErrorHandler, Test_Session_Middleware_InitializeError_DefaultErrorHandler, and Test_Session_Middleware_InitializeError_ReturnsHandlerErrorWhenUnwritten to validate middleware initialization error handling.
    • Added new tests for Test_Middleware_FinalizeSession_NormalSavePath, Test_Middleware_FinalizeSession_DestroyedPathSkipsSave, and Test_Middleware_FinalizeSession_SaveErrorStillReleasesSession to verify the finalizeSession behavior.
  • middleware/session/store.go
    • Ensured sess.Release() is called in getSession if sess.Reset() fails when an absolute-expired session is encountered.
    • Modified GetByID to always call sess.Release() before returning ErrSessionIDNotFoundInStore after attempting to destroy an expired session.
  • middleware/session/store_test.go
    • Added trackingStorage to monitor Delete calls in tests.
    • Introduced seedExpiredSessionInStore helper function to set up expired sessions for testing.
    • Added Test_Store_getSession_ExpiredResetFailureReleasesSession to confirm session release when Reset() fails on an expired session.
    • Added Test_Store_GetByID_ExpiredDestroySuccessReleasesSession to confirm session release when an expired session is destroyed via GetByID.
Activity
  • The author, gaby, provided a detailed motivation for the changes, highlighting the prevention of session-object leaks and panics.
  • The description outlines specific code modifications, including making initialize return an error, adding finalizeSession(), and hardening Store methods.
  • Testing involved running unit tests for the session package with focused cases, full go test ./middleware/session, and make test, all of which passed.
  • Code quality checks (make generate, make betteralign, make modernize, make format, make lint) were performed and succeeded.
  • An make audit was run, which failed due to unrelated standard-library vulnerabilities in Go 1.25.1, as noted by the author.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ReneWerner87 ReneWerner87 added this to the v3 milestone Feb 7, 2026
@ReneWerner87 ReneWerner87 added this to v3 Feb 7, 2026
@gaby gaby changed the title 🐛 bug: harden session middleware and store lifecycle error handling 🐛 bug: harden session middleware lifecycle and error handling Feb 7, 2026
@codecov
Copy link

codecov bot commented Feb 7, 2026

Codecov Report

❌ Patch coverage is 96.29630% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.16%. Comparing base (4df2fce) to head (fe63faf).
⚠️ Report is 30 commits behind head on main.

Files with missing lines Patch % Lines
middleware/session/session.go 75.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4059      +/-   ##
==========================================
+ Coverage   91.09%   91.16%   +0.06%     
==========================================
  Files         119      119              
  Lines       11184    11224      +40     
==========================================
+ Hits        10188    10232      +44     
+ Misses        630      628       -2     
+ Partials      366      364       -2     
Flag Coverage Δ
unittests 91.16% <96.29%> (+0.06%) ⬆️

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
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 significantly hardens the session middleware by improving error handling and fixing several potential resource leaks. While the changes are well-implemented, replacing panics with proper error propagation and ensuring session objects are always released back to the pool, a high-severity issue remains. The middleware instance is returned to the pool while a reference to it still exists in the request context's locals, which can lead to cross-request session data leakage if other middlewares access the session after the main handler chain has completed. It is recommended to clear the context local reference before releasing the middleware instance. Additionally, consider improving context propagation during session destruction in middleware/session/store.go.

Copy link
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 hardens the session middleware/store lifecycle to prevent pooled Session/Middleware objects from leaking across request/error paths, and adds regression tests around those paths.

Changes:

  • Convert (*Middleware).initialize to return an error and route init failures through the configured ErrorHandler/DefaultErrorHandler instead of panicking.
  • Ensure sessions are always released back to the pool on terminal/error paths (finalizeSession, extra Release() calls in store error branches).
  • Add regression tests for initialization, context-local cleanup, and store expiry/destroy behaviors.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
middleware/session/middleware.go Switch init to error-return and add finalizeSession() to guarantee session release and locals cleanup.
middleware/session/session.go Add a stored context (gctx) so Destroy() can honor GetByID’s context; clear it on release.
middleware/session/store.go Release sessions on absolute-expiry reset failure; ensure GetByID releases sessions on expiry destroy path and uses gctx.
middleware/session/middleware_test.go Add tests for locals cleanup, init error handling, and finalize lifecycle behavior.
middleware/session/store_test.go Add tests for expiry/reset failure release, expiry destroy release, and destroy context propagation.

Comment on lines +325 to +329
reused := acquireSession()
require.Nil(t, reused.ctx)
require.Nil(t, reused.config)
require.Empty(t, reused.id)
reused.Release()
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

These assertions don’t actually verify that the session involved in the failing store.Get path was released back to the pool: sync.Pool may return a different (or newly allocated) Session that already has zero values, so the test can pass even if the original session leaked. Consider making the test deterministic (e.g., temporarily swapping sessionPool with a test pool and disabling t.Parallel() for this test, or adding explicit instrumentation/counters around release paths).

Copilot uses AI. Check for mistakes.
Comment on lines +350 to +354
reused := acquireSession()
require.Nil(t, reused.ctx)
require.Nil(t, reused.config)
require.Empty(t, reused.id)
reused.Release()
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

Same issue as above: acquiring a session from sync.Pool and checking for zero-values doesn’t prove the expired GetByID path released the specific session it allocated, since sync.Pool can return a different/new object. Consider a deterministic approach (test pool swap, counters, or pointer identity under controlled conditions) so this test fails if the session isn’t released.

Copilot uses AI. Check for mistakes.
Comment on lines +662 to +666
m := acquireMiddleware()
require.Nil(t, m.Session)
require.Nil(t, m.ctx)
require.Nil(t, m.config.Store)
releaseMiddleware(m)
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

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

This pool check isn’t a reliable assertion that the middleware instance used during the request was released: sync.Pool may return a different (or newly allocated) Middleware with nil fields, so the test can pass even if the original middleware wasn’t released on init error. Consider asserting observable behavior instead (e.g., that the request doesn’t leave a middleware in c.Locals, or adding deterministic pooling instrumentation in tests).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants