Google ADK DatabaseSessionService: "TypeError: fromisoformat: argument must be str" on SQLite
get_session() fails when a SQLite session table holds float timestamps. Why it happens, how to reproduce it, and the version that handles it.
Disclosure: I work on MemorySync (I'm Mohammed, the founder). I drafted this page with AI assistance and checked it against the GitHub issue, the fix commit and the ADK source listed under Sources on Nov 11, 2026. Code status: I ran the repro offline on google-adk 2.3.0 (SQLAlchemy 2.0.41) and google-adk 2.14.0 (SQLAlchemy 2.1.8) with sqlite+aiosqlite, Python 3.13, no agent and no model. To get a float into the table I wrote it directly with Python's sqlite3; I didn't run SqliteSessionService, adk web or adk api_server against the same file, or any MemorySync code.
You use ADK's DatabaseSessionService with a SQLite URL, and reading a session back fails:
TypeError: fromisoformat: argument must be str
The traceback ends inside SQLAlchemy's str_to_datetime. That's google/adk-python issue #6352, "DatabaseSessionService.get_session() raises TypeError: fromisoformat: argument must be str", reported on google-adk 2.3.0.
MemorySync doesn't fix this bug. It's in how ADK's SQL session store reads timestamps, and you need the fix below with or without MemorySync.
Skip the memory plumbing around this fix. Sessions are ADK's short-term store. Once they read back cleanly, the MemorySync Google ADK guide shows a
BaseMemoryServicefor memory that lasts across sessions. It doesn't replace your session service. When you're ready, see MemorySync. Founding offer: use code FOUNDING30 for 30% off Starter for your first 3 months (Settings → Billing).
Status (Nov 11, 2026)
- #6352 was opened Jul 9, 2026 and closed as completed on Jul 16, 2026 by commit
2da09e6("fix: handle sqlite float timestamps in PreciseTimestamp", merging PR #6355). - GitHub's compare view shows that commit included in the v2.5.0 and v2.6.0 tags. I ran 2.14.0 (the latest on PyPI on Nov 11, 2026), and it reads the same file without error.
Why it happens
From the issue thread: ADK's SQL schema stores timestamps in a PreciseTimestamp column backed by SQLAlchemy DateTime. On SQLite, SQLAlchemy expects those values as text and parses them with fromisoformat. If a row holds a REAL (a Unix epoch float), the parser gets a float and raises.
How does a float get there? The thread's leading explanation, which the reporter confirmed, is a second writer: ADK's other SQLite backend, SqliteSessionService, stores timestamps as raw floats. If it and DatabaseSessionService touch the same database file, the SQL service can't read what the other one wrote. A maintainer also noted in the thread: "if SQLite is your main database we recommend just use the SqliteSessionService."
Step 1: Reproduce it
This creates a session with DatabaseSessionService, puts a float in the update_time column (standing in for the other writer), then reads the session back with a fresh service:
import asyncio, os, sqlite3, time
from google.adk.sessions import DatabaseSessionService
DB = "/tmp/adk_repro.db"
if os.path.exists(DB):
os.remove(DB)
async def main():
svc = DatabaseSessionService(db_url=f"sqlite+aiosqlite:///{DB}")
await svc.create_session(app_name="app", user_id="u1", session_id="s1")
con = sqlite3.connect(DB)
con.execute("update sessions set update_time=? where id='s1'", (time.time(),))
con.commit()
con.close()
svc2 = DatabaseSessionService(db_url=f"sqlite+aiosqlite:///{DB}")
try:
s = await svc2.get_session(app_name="app", user_id="u1", session_id="s1")
print("OK", s.last_update_time)
except Exception as e:
print("FAILED", type(e).__name__, e)
asyncio.run(main())
You need the db extra: pip install "google-adk[db]" plus aiosqlite. What I got:
google-adk 2.3.0, SQLAlchemy 2.0.41: FAILED TypeError fromisoformat: argument must be str
google-adk 2.14.0, SQLAlchemy 2.1.8: OK 1794409299.836908
Step 2: Upgrade ADK
The fix overrides result_processor on PreciseTimestamp so a float is converted to a datetime before SQLAlchemy's text parser sees it. The thread explains why process_result_value alone wasn't enough: the base DateTime processor runs first and fails on the float.
pip install -U "google-adk[db]"
Then check that result_processor is defined in google/adk/sessions/schemas/shared.py in your installed package if you want to be sure you have the fix.
Step 3: Use one session backend per database file
Upgrading stops the crash, but two services writing different timestamp formats into one file is still worth fixing:
- SQLite only: use
SqliteSessionService, as the maintainer suggested, and point nothing else at that file. - Postgres, MySQL or another SQL database: use
DatabaseSessionService, and give it its own database. adk webandadk api_server: per a comment in the thread, both fall back to the same per-agent SQLite session store unless you pass--session_service_uri. If you pass it to one process and not the other, they can end up on different stores. Pass the same value to both.
Skip the plumbing with MemorySync
Disclosure: I build MemorySync.
This doesn't change the fix above: DatabaseSessionService is still your session store, so upgrade it as in Step 2. The MemorySync Google ADK guide documents MemorySyncMemoryService, an ADK BaseMemoryService you pass as Runner(memory_service=...) next to whatever session_service you use. You call add_session_to_memory(session) after a conversation, and ADK's preload_memory tool brings that user's memories into later sessions. It requires google-adk 2.0+ and Python 3.10+ and lists google-adk-memorysync 1.1.0.
From the guide:
Unverified (not run):
pip install google-adk-memorysync google-adk
from google.adk.runners import Runner
from google_adk_memorysync import MemorySyncMemoryService
memory_service = MemorySyncMemoryService() # reads MEMORYSYNC_API_KEY
runner = Runner(
agent=agent,
app_name="support",
session_service=session_service, # your DatabaseSessionService
memory_service=memory_service,
)
# after a conversation:
session = await runner.session_service.get_session(
app_name="support", user_id="customer-7", session_id="thread-42"
)
await memory_service.add_session_to_memory(session)
Snippet adapted from the MemorySync Google ADK guide, which uses InMemorySessionService; I swapped in your session service and haven't run it for this page.
Try it: MemorySync is optional here: the steps above work without it. If you want the memory layer from the snippet, see MemorySync, create an API key in the dashboard and drop the snippet into your agent.
FAQ
I deleted the database and it still fails. Why? The reporter saw the same thing. A fresh file only helps if nothing else writes floats into it; check every process and service that uses that path.
Do I lose sessions by switching service? The two services use different schemas, so don't point a new service at the old file and expect it to read everything. Plan a migration or start a new file.
Is this a SQLAlchemy bug?
No. SQLAlchemy is doing what a DateTime column on SQLite does. The fix is on ADK's side, in PreciseTimestamp.
Sources
- github.com/google/adk-python/issues/6352 (opened 2026-07-09, closed as completed 2026-07-16, 11 comments; root cause,
SqliteSessionServicefloat timestamps, maintainer recommendation,--session_service_urinote; read 2026-10-30) - Commit 2da09e60d7d03d27bf9aa721db37cf0475157c21, "fix: handle sqlite float timestamps in PreciseTimestamp" (PR #6355), and GitHub compare against v2.5.0 and v2.6.0 (read 2026-10-30)
- google-adk 2.14.0 source:
google/adk/sessions/schemas/shared.py(read 2026-11-11) - Offline runs on google-adk 2.3.0 and 2.14.0, Python 3.13 (2026-11-11)
- MemorySync Google ADK guide: docs.memorysync.io/guides/google-adk (fetched 2026-10-30)
Try it
For an overview of MemorySync, see the MemorySync homepage.
Next step: read the MemorySync Google ADK guide, then see MemorySync. Founding offer: use code FOUNDING30 for 30% off Starter for your first 3 months (Settings → Billing).
About the author
- Building MemorySync (memorysync.io) — persistent memory infrastructure for AI agents, Cursor, and Claude Code.
Comments
Join the discussionNo comments yet. Be the first to comment.
