Skip to content

fix(sessions): normalize session_id before the duplicate check in InMemorySessionService - #6892

Open
MUHAMMEDHAFEEZ wants to merge 1 commit into
google:mainfrom
MUHAMMEDHAFEEZ:fix/in-memory-session-strip-before-duplicate-check
Open

fix(sessions): normalize session_id before the duplicate check in InMemorySessionService#6892
MUHAMMEDHAFEEZ wants to merge 1 commit into
google:mainfrom
MUHAMMEDHAFEEZ:fix/in-memory-session-strip-before-duplicate-check

Conversation

@MUHAMMEDHAFEEZ

Copy link
Copy Markdown

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

Problem:
InMemorySessionService._create_session_impl() checks whether a session already
exists using the raw session_id, and only strips whitespace from it
afterward, right before using it as the storage key. A client-supplied id
that differs from an existing one only by surrounding whitespace (e.g. a
trailing "\n" picked up from a file, CSV column, or env var) therefore
misses the duplicate check and silently overwrites the existing session,
wiping its events and state, with no exception and no log line.

sqlite_session_service already strips the id before running its
duplicate check, so this is an inconsistency between backends rather than
intended behavior.

Solution:
Move the strip() to the top of _create_session_impl, before the
duplicate-id check, and simplify the later normalization (which no longer
needs to re-strip) to just falling back to a generated id when blank. Net
change is -3 lines.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Added two tests to tests/unittests/sessions/test_session_service.py,
instantiating InMemorySessionService directly (this is backend-specific
behavior, not something the shared cross-backend session_service fixture
should assert, since database/redis normalize differently and that's a
separate, larger discussion):

  • test_create_session_with_padded_duplicate_id_raises_error — creates a
    session, then asserts that creating again with the same id padded in
    whitespace raises AlreadyExistsError instead of clobbering the original
    session's state.
  • test_create_session_with_blank_id_generates_one — asserts a
    whitespace-only id is treated as no id (still generates one), guarding
    the simplified fallback logic.

I confirmed the first test fails on the unfixed code (DID NOT RAISE AlreadyExistsError) and passes after the fix, so it actually exercises the
bug rather than passing vacuously.

$ pytest tests/unittests/sessions/test_session_service.py
================== 252 passed, 2 xfailed, 3 warnings in 4.88s ==================

The 2 xfailed are pre-existing, documented Redis divergences unrelated to
this change.

Also ran pyink --check, ruff check, isort --check, codespell, and
mypy --strict on both changed files — all clean.

Manual End-to-End (E2E) Tests:

Ran the reproduction from the issue directly against InMemorySessionService:

Before the fix:

before: order-42 2 {'cart': ['book']}
second create returned: 'order-42' (no exception)
after : order-42 0 {'cart': []}

(the second create_session call silently destroyed the first session's
2 events and its cart state)

After the fix:

before: order-42 2 {'cart': ['book']}
second create raised: AlreadyExistsError - Session with id order-42 already exists.
after : order-42 2 {'cart': ['book']}

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

Scope note: the issue also flagged that database and redis backends
normalize session_id differently (or not at all), which is a separate,
larger behavioral question across BaseSessionService implementations.
This PR intentionally only fixes the in_memory inconsistency against
sqlite's existing (correct) behavior, and leaves the cross-backend
normalization contract as a follow-up.

@google-cla

google-cla Bot commented Aug 25, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

…emorySessionService

_create_session_impl() checked for an existing session using the raw
session_id, then only stripped it afterward before using it as the storage
key. A caller-supplied id that differs from an existing one only by
surrounding whitespace passed the duplicate check and then silently
overwrote the existing session's events and state, returning a normal
Session with no error.

sqlite_session_service already strips before checking; this brings
InMemorySessionService in line with it.

Fixes google#6887
@MUHAMMEDHAFEEZ
MUHAMMEDHAFEEZ force-pushed the fix/in-memory-session-strip-before-duplicate-check branch from 7665cd0 to 69ef8a3 Compare August 25, 2026 02:19
@MUHAMMEDHAFEEZ
MUHAMMEDHAFEEZ marked this pull request as ready for review August 25, 2026 02:25
@MUHAMMEDHAFEEZ

Copy link
Copy Markdown
Author

Hi @DeanChensj , just checking in on this PR. It’s ready for review and all required checks are currently passing.

Whenever you have a chance, I’d appreciate your feedback. Happy to make any changes you think are needed. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants