Repository navigation
DatabaseSessionService.get_session returns all events when num_recent_events=0 #5730
Description
🔴 Required Information
Describe the Bug:
DatabaseSessionService.get_session(..., config=GetSessionConfig(num_recent_events=0)) is documented to return no events (see GetSessionConfig docstring in src/google/adk/sessions/base_session_service.py: "if 0, no events are returned").
However, when num_recent_events=0 is passed, all events of the session are returned instead of an empty list.
This appears to be caused by a truthy check on num_recent_events in src/google/adk/sessions/database_session_service.py (around line 523):
if config and config.num_recent_events: # ← `0` is falsy, so this branch is skipped
stmt = stmt.limit(config.num_recent_events)Because 0 is falsy in Python, the LIMIT clause is never appended when num_recent_events=0, and the query returns every event for the session.
The other in-tree implementations appear to handle 0 correctly:
InMemorySessionService(src/google/adk/sessions/in_memory_session_service.py:204-211): usesis not Noneand explicitly assignsevents = []whennum_recent_events == 0.SqliteSessionService(src/google/adk/sessions/sqlite_session_service.py:264-271): usesis not Nonefor theLIMITclause, plus an explicit early return for== 0.
So this issue appears to be specific to DatabaseSessionService (SQLAlchemy backend).
Steps to Reproduce:
-
Install
google-adk(reproduced on 1.33.0 / currentmain) andaiosqlite. -
Run the following script (uses SQLite in-memory, no external DB needed):
import asyncio
from google.genai import types
from google.adk.events.event import Event
from google.adk.sessions.base_session_service import GetSessionConfig
from google.adk.sessions.database_session_service import DatabaseSessionService
async def main():
svc = DatabaseSessionService(db_url="sqlite+aiosqlite:///:memory:")
app, user, sid = "app", "user_1", "session_1"
session = await svc.create_session(app_name=app, user_id=user, session_id=sid)
for i in range(5):
ev = Event(
invocation_id=f"inv_{i}",
author="user" if i % 2 == 0 else "agent",
content=types.Content(
role="user" if i % 2 == 0 else "model",
parts=[types.Part(text=f"event #{i}")],
),
)
await svc.append_event(session=session, event=ev)
got = await svc.get_session(
app_name=app,
user_id=user,
session_id=sid,
config=GetSessionConfig(num_recent_events=0),
)
print("num_recent_events=0 -> events len =", len(got.events))
asyncio.run(main())Expected Behavior:
num_recent_events=0 -> events len = 0
This matches the behavior of InMemorySessionService for the equivalent call.
Observed Behavior:
num_recent_events=0 -> events len = 5
All 5 events are returned.
Testing across multiple num_recent_events values suggests that 0 is the only problematic case:
num_recent_events= None -> events len = 5 # OK (no filter)
num_recent_events= 0 -> events len = 5 # Incorrect behavior (should be 0)
num_recent_events= 2 -> events len = 2 # OK
num_recent_events= 5 -> events len = 5 # OK
The issue is reproducible regardless of the underlying database, because the affected branch is in Python (the LIMIT clause is simply never appended to the SQLAlchemy statement).
SQLite is used here only for convenience; PostgreSQL, MySQL, and MariaDB appear to be affected in the same way.
Environment Details:
- ADK Library Version (
pip show google-adk): 1.33.0 - Desktop OS: Linux (WSL2, Ubuntu)
- Python Version (
python -V): Python 3.12.3
Model Information:
- Are you using LiteLLM: No
- Which model is being used: gemini-3.1-flash-lite)
Thanks for taking a look.
Activity
fix(sessions): respect num_recent_events=0 in DatabaseSessionService
fix(sessions): respect num_recent_events=0 in DatabaseSessionService
surajksharma07 commentedon May 18, 2026
@tiino the falsy check on num_recent_events at line 523 is exactly the problem, and swapping it to is not None paired with an explicit == 0 early return (the same pattern SqliteSessionService already uses) is the right fix.
Since you've already got PR #5731 open, could you verify it covers both parts of that change and run your repro script across num_recent_events=0, 2, and None to confirm the behavior holds end-to-end?
Thorough testing across those three cases would really help move the PR forward for review!
tiino commentedon May 19, 2026
Thanks for the review, @surajksharma07!
Pushed a follow-up commit (
edce3f54) that adds the early return you suggested. The structure now mirrorsSqliteSessionService.get_sessiondirectly:The
LIMIT 0path alone would already return zero rows on any major SQL backend, but skipping theexecute()call entirely avoids an unnecessary round-trip — same reasoning asSqliteSessionService(skipsexecute_fetchall) andVertexAiSessionService(skips theevents.listAPI call). That matters more in this service's typical remote-DB deployments (PostgreSQL / MySQL).On testing, I extended
test_get_session_with_configto covernum_recent_events=2. The parametrized test now runsNone,0,2, and3against all four session backends (InMemorySessionService,InMemorySessionServicewith light-copy,DatabaseSessionService,SqliteSessionService).I also ran the end-to-end repro across the three values you called out, using SQLite in-memory backing the
DatabaseSessionService:Output on current
main(before fix):Output on this branch (after fix + early return):
surajksharma07 commentedon May 25, 2026
Thanks for the thorough follow-up @tiino — the two-block structure (is not None for the LIMIT + == 0 early return to skip execute()) is exactly right and mirrors SqliteSessionService line-for-line.
The reasoning around avoiding the unnecessary DB round-trip is especially valid for the typical remote PostgreSQL/MySQL deployment scenario.
One thing worth noting: there are now two PRs open for the same issue (#5731 yours and #5736 from @mangod12), so it's worth taking a quick look at the other to see if the approaches differ meaningfully — maintainers will likely need to pick one or ask for a consolidation.
The parametrized test coverage across all four backends (None, 0, 2, 3) is exactly what reviewers will want to see, and the before/after repro output makes the fix straightforward to validate end-to-end.
Team is looking more into it.
GWeale commentedon Jun 17, 2026
Fixed on main in commit d9a672e (via #5965, also #5731): get_session now uses an is-not-None check, so num_recent_events=0 returns zero events instead of the full history. Thanks for the report and the fix. Closing as landed.